ntl-11.5.1/0000755417616742025610000000000014064716022014155 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/0000755417616742025610000000000014064716023014745 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/FFT.cpp0000644417616742025610000025706514064716022016106 0ustar gid-shoupvpug-gid-shoupv #include #include #ifdef NTL_ENABLE_AVX_FFT #include #include #endif /******************************************************************** This is an implementation of a "small prime" FFT, which lies at the heart of ZZ_pX and zz_pX arithmetic, and impacts many other applications as well (such as arithmetic in ZZ_pEX, zz_pEX, and ZZX). The algorithm is a Truncated FFT based on code originally developed by David Harvey. David's code built on the single-precision modular multiplication technique introduced in NTL many years ago, but also uses a "lazy multiplication" technique, which reduces the number of "correction" steps that need to be performed in each butterfly (see below for more details). It also implements a version of the Truncated FFT algorithm introduced by Joris van der Hoeven at ISSAC 2004. Also see "A cache-friendly truncated FFT", David Harvey, Theoretical Computer Science Volume 410, Issues 27-29, 28 June 2009, Pages 2649-2658. I have almost completely re-written David's original code to make it fit into NTL's software framework; however, all of the key logic is still based on David's code. David's original code also implemented a 2D transformation which is more cache friendly for *very* large transforms. However, my experimens indicated this was only beneficial for transforms of size at least 2^20, and so I did not incorporate this variant. Here is the Copyright notice from David's original code: ============================================================================== fft62: a library for number-theoretic transforms Copyright (C) 2013, David Harvey All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ============================================================================== SINGLE-PRECISION MODULAR ARITHMETIC The implementation of arithmetic modulo n, where n is a "word sized" integer is critical to the performance of the FFT. Such word-sized modular arithmetic is used throughout many other parts of NTL, and is a part of the external, documented interface. As NTL was initially built on top of Arjen Lenstra's LIP software, I stole a lot of ideas from LIP. One very nice ideas was LIP's way of handling single-precision modular arithmetic. Back in those days (the early 1990's), I was targeting 32-machines, mainly SPARC stations. LIP's stratgey was to restrict n to 30 bits, and to compute a*b % n, where 0 <= a, b < n, the follwong was computed: long q = long(double(a) * double(b) / double(n)); long r = a*b - q*n; if (r >= n) r -= n; else if (r < 0) r += n; With quite reasonable assumptions about floating point (certainly, anything even remotely close to IEEE 64-bit doubles), the computation of q always gives the true quotient floor(a*b / n), plus or minus 1. The computation of r is done modulo the 2^{word size}, and the following if/then/else adjusts r as necessary. To be more portable, some of these computations should really be done using unsigned arithmetic, but that is not so important here. Also, the adjustment steps can be replaced by simple non-branching instrictions sequences involving SHIFT, AND, and ADD/SUB instructions. On some modern machines, this is usually faster and NTL uses this non-branching strategy. However, on other machines (modern x86's are an example of this), conditional move instructions can be used in place of branching, and this code can be faster than the non-branching code. NTL's performance-tuning script will figure out the best way to do this. Other simple optimizations can be done, such as precomputing 1/double(n) when n remains fixed for many computations, as is often the case. Note also that this strategy works perfectly well even when a or b are larger than n, but the quotient itself is bounded by 2^30. This strategy worked well for many years. I had considered employing "Montgomery multiplication", but did not do so for a couple of reasons: 1) it would require non-portable code, because Montgomery multiplication requires the computation of two-word products, 2) I did not like the idea of working with "alternative representations" for integers mod n, as this would make the interfaces more awkward. At some point in the early 2000's, this strategy was starting to slow things down, as floating point arithmetic, especially the integer/floating point conversions, was starting to slow down relative to integer arithmetic. This was especially true on x86 machines, which by this time was starting to become the most important target. As it happens, later in the 2000's, as the x86 platforms started to use SSE instructions in lieu of the old x87 FPU instructions, this speed differential again became less of a problem. Nevertheless, I introduced some new techniques that speed things up across a variety of platforms. I introduced this new technique in NTL 5.4 back in 2005. I never claimed it was particularly new, and I never really documented many details about it, but since then, it has come to be known as "Shoup multiplcation" in a few papers, so I'll accept that. :-) The paper "Faster arithmetic for number-theoretic transforms" [David Harvey, J. Symb. Comp. 60 (2014)] seems to be the first place where it is discussed in detail, and Harvey's paper also contains some improvements which I discuss below. The basic idea is that in many computations, not only n, but one of the arguments, say b, remains fixed for many computatations of a*b % n, and so we can afford to do a little precomputation, based on b and n, to speed things up. This approach does require the ability to compute double-word products (actually, just the high word of the product), but it still presents the same basic interface as before (i.e., no awkward, alternative representations); moreover, on platforms where we can't get double-word products, the implementation falls back to the old floating point strategy, and client code need not be aware of this. The basic idea is this: suppose 0 <= n < 2^w, and 0 <= a < 2^w, and 0 <= b < n. We precompute bninv = floor(2^w*b/n). Then if we compute q = floor(a*bninv/2^w), it can be argued that q is either floor(a*b/n), or is 1 too small. The computation of bninv can be done using the floating point techniques described above. The computation of q can be done by computing the high word of a double-word product (it helps if bninv is left-shifted an appropriate amount first). Once we have q, we can compute a*b - q*n as before, and adjust (but now only one adjustment is needed). So after the precomputation. the whole operation takes 3 multiplies (one doube-word and two single-word), and a small handful of simple instructions (adds, shifts, etc). Moreover, two of the three multiplies can start in parallel, on platforms where this is possible. David Harvey noticed that because on modern machines, multiplies are really not that slow compared to additions, the cost of all of the adjustments (in the MulMod, as well as in the AddMod and SubMod's in the basic FFT butterfly steps) starts to dominate the cost of the FFT. Indeed, with a straightforward implementation of the above ideas, there are three multiplies and three adjustment steps in each butterfly step. David's idea was to work with redundant representations mod n, in the range [0..4*n), and thus reduce the number of adjustments per butterfly from three to one. I've implemented this idea here, and it does indeed make a significant difference, which is even more pronounced when all of the FFT multipliers b and corresponding bninv values are precomputed. My initial implementation of David's ideas (v6.0 in 2013) only implemented his approach with these precomputated tables: it seemed that without these tables, it was not a significant improvement. However, I later figured out how to reduce the cost of computing all the necessary data "on the fly", in a way that seems only slightly (10-15%) slower overall. I introduced this in v9.1 in 2015, and set things up so that now the pre-computed tables are still used, but not exclusively, in such a way as to reduce the memory used by these tables for very large polynomials (either very high degree or lots of FFT primes). The idea here is simple, but I haven't seen it discussed elsewhere, so I'll document the basic idea here. Suppose we have the preconditioners for a and b, and want a*b % n along with the preconditioner for a*b % n. For a, let us suppose that we have both q1 and r1, where: 2^w*a = n*q1 + r1 We can obtain both q1 and r1 using floating point techniques. Step 1. Compute a*b % n, using the integer-only MulMod, using either the preconditioner for either a or b. Step 2. Compute q2 and r2 such that r1*b = n*q2 + r2 We can obtain these using the integer-only MulMod, preconditioned on b. Actually, we only need q2, not r2. Step 3. Compute q3 = q1*b + q2 mod 2^w which we can compute with just a single-word multiply and an addition. One can easily show that the value q3 computed above is indeed the preconditioner for a*b % n. Note that, in theory, if the computation in Step 2 is done using the preconditioner for a (i.e., q1), then the multiplication q1*b in Step 3 should not really be necessary (assuming that computing both high and low words of a doube-wprd product is no more expensive than just computing the low word). However, none of the compilers I've used have been able to perform that optimization (in NTL v11.1, I added code that hand-codes this optimization). 64-BIT MACHINES Current versions of NTL use (by default) 60-bit moduli based on all-integer arithemtic. Prior to v9.0 of NTL, on 64 bits, the modulus n was restricted to 50 bits, in order to allow the use of double-precision techniques, as double's have 53 bits of precision. However, NTL now supports 60-bit moduli. Actually, 62 bits can be supported by setting the NTL_MAXIMIZE_SP_NBITS configuraton flag, but other things (namely, the TBL_REM implementation in lip.cpp) start to slow down if 62 bits are used, so 60 seems like a good compromise. Currently, 60-bit moduli are available only when compiling NTL with GMP, and when some kind of extended integer of floating point arithmetic is available. FUTURE TRENDS * The following papers https://eprint.iacr.org/2017/727 https://eprint.iacr.org/2016/504 https://eprint.iacr.org/2015/382 present FFTs that access the pre-computed tables in a somewhat more efficent fashion, so that we only need to read from the tables O(n) times, rather than O(n log n) times. I've partially implemented this, and have gotten mixed results. For smallish FFT's (below k=10 or 11), this code is somewhat slower. For larger FFT's (say, k=17), I see a speedup of 3-10%. ********************************************************************/ #define NTL_FFT_BIGTAB_LIMIT (180) #define NTL_FFT_BIGTAB_MAXROOT (17) #define NTL_FFT_BIGTAB_MINROOT (7) // table sizes are bounded by 2^bound, where // bound = NTL_FFT_BIGTAB_MAXROOT-index/NTL_FFT_BIGTAB_LIMIT. // Here, index is the index of an FFT prime, or 0 for a user FFT prime. // If bound <= NTL_FFT_BIGTAB_MINROOT, then big tables are not used, // so only the first // (NTL_FFT_BIGTAB_MAXROOT-NTL_FFT_BIGTAB_MINROOT)*NTL_FFT_BIGTAB_LIMIT // FFT primes will have big tables. // NOTE: in newer versions of NTL (v9.1 and later), the BIGTAB // code is only about 5-15% faster than the non-BIGTAB code, so // this is not a great time/space trade-off. // However, some futher optimizations may only be implemented // if big tables are used. // NOTE: NTL_FFT_BIGTAB_MAXROOT is set independently of the parameter // NTL_FFTMaxRoot defined in FFT.h (and which is typically 25). // The space for the LazyTable FFTMultipliers could be reduced a bit // by using min(NTL_FFT_BIGTAB_MAXROOT, NTL_FFTMaxRoot) + 1 for the // size of these tables. NTL_START_IMPL class FFTVectorPair { public: Vec wtab_precomp; Vec wqinvtab_precomp; }; typedef LazyTable FFTMultipliers; #ifdef NTL_ENABLE_AVX_FFT class pd_FFTVectorPair { public: AlignedArray wtab_precomp; AlignedArray wqinvtab_precomp; }; typedef LazyTable pd_FFTMultipliers; #endif class FFTMulTabs { public: #ifndef NTL_ENABLE_AVX_FFT long bound; FFTMultipliers MulTab; #else pd_FFTMultipliers pd_MulTab[2]; #endif }; void FFTMulTabsDeleterPolicy::deleter(FFTMulTabs *p) { delete p; } FFTTablesType FFTTables; // a truly GLOBAL variable, shared among all threads long IsFFTPrime(long n, long& w) { long m, x, y, z; long j, k; if (n <= 1 || n >= NTL_SP_BOUND) return 0; if (n % 2 == 0) return 0; if (n % 3 == 0) return 0; if (n % 5 == 0) return 0; if (n % 7 == 0) return 0; m = n - 1; k = 0; while ((m & 1) == 0) { m = m >> 1; k++; } for (;;) { x = RandomBnd(n); if (x == 0) continue; z = PowerMod(x, m, n); if (z == 1) continue; x = z; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; if (j == k) break; } /* x^{2^k} = 1 mod n, x^{2^{k-1}} = -1 mod n */ long TrialBound; TrialBound = m >> k; if (TrialBound > 0) { if (!ProbPrime(n, 5)) return 0; /* we have to do trial division by special numbers */ TrialBound = SqrRoot(TrialBound); long a, b; for (a = 1; a <= TrialBound; a++) { b = (a << k) + 1; if (n % b == 0) return 0; } } /* n is an FFT prime */ for (j = NTL_FFTMaxRoot; j < k; j++) { x = MulMod(x, x, n); } w = x; return 1; } static void NextFFTPrime(long& q, long& w, long index) { static long m = NTL_FFTMaxRootBnd + 1; static long k = 0; // m and k are truly GLOBAL variables, shared among // all threads. Access is protected by a critical section // guarding FFTTables static long last_index = -1; static long last_m = 0; static long last_k = 0; if (index == last_index) { // roll back m and k...part of a simple error recovery // strategy if an exception was thrown in the last // invocation of UseFFTPrime...probably of academic // interest only m = last_m; k = last_k; } else { last_index = index; last_m = m; last_k = k; } long t, cand; for (;;) { if (k == 0) { m--; if (m < 5) ResourceError("ran out of FFT primes"); k = 1L << (NTL_SP_NBITS-m-2); } k--; cand = (1L << (NTL_SP_NBITS-1)) + (k << (m+1)) + (1L << m) + 1; if (!IsFFTPrime(cand, t)) continue; q = cand; w = t; return; } } long CalcMaxRoot(long p) { p = p-1; long k = 0; while ((p & 1) == 0) { p = p >> 1; k++; } if (k > NTL_FFTMaxRoot) return NTL_FFTMaxRoot; else return k; } #ifndef NTL_WIZARD_HACK SmartPtr Build_zz_pInfo(FFTPrimeInfo *info); #else SmartPtr Build_zz_pInfo(FFTPrimeInfo *info) { return 0; } #endif void UseFFTPrime(long index) { if (index < 0) LogicError("invalud FFT prime index"); if (index >= NTL_MAX_FFTPRIMES) ResourceError("FFT prime index too large"); if (index+1 >= NTL_NSP_BOUND) ResourceError("FFT prime index too large"); // largely acacedemic, but it is a convenient assumption do { // NOTE: thread safe lazy init FFTTablesType::Builder bld(FFTTables, index+1); long amt = bld.amt(); if (!amt) break; long first = index+1-amt; // initialize entries first..index long i; for (i = first; i <= index; i++) { UniquePtr info; info.make(); long q, w; NextFFTPrime(q, w, i); long bigtab_index = -1; #ifdef NTL_FFT_BIGTAB bigtab_index = i; #endif InitFFTPrimeInfo(*info, q, w, bigtab_index); info->zz_p_context = Build_zz_pInfo(info.get()); bld.move(info); } } while (0); } #ifdef NTL_FFT_LAZYMUL // we only honor the FFT_LAZYMUL flag if either the SPMM_ULL_VIABLE or LONGLONG_SP_MULMOD // flags are set #if (!defined(NTL_SPMM_ULL_VIABLE) && !defined(NTL_LONGLONG_SP_MULMOD)) #undef NTL_FFT_LAZYMUL // raise an error if running the wizard #if (defined(NTL_WIZARD_HACK)) #error "cannot honor NTL_FFT_LAZYMUL" #endif #endif #endif #ifdef NTL_FFT_LAZYMUL // FFT with lazy multiplication #ifdef NTL_CLEAN_INT #define NTL_FFT_USEBUF #endif // DIRT: with the lazy multiplication strategy, we have to work // with unisgned long's rather than long's. To avoid unnecessary // copying, we simply cast long* to unsigned long*. // Is this standards compliant? Does it evoke Undefined Behavior? // The C++ standard before C++14 were actually somewhat inconsistent // on this point. // In all versions of the C++ and C standards, the "strict aliasing" // rules [basic.lval] have always said that signed/unsigned can // always alias each other. So this does not break the strict // aliasing rules. However, prior to C++14, the section // on Lvalue-to-rvalue conversion [conv.lval] said that // this was actually UB. This has been cleared up in C++14, // where now it is no longer UB. Actally, it seems that the change // to C++14 was cleaning up an inconsistency in the standard // itself, and not really a change in the language definition. // In practice, it does make a significant difference in performance // to avoid all these copies, so the default is avoid them. // See: https://stackoverflow.com/questions/30048135/efficient-way-to-bit-copy-a-signed-integer-to-an-unsigned-integer // See: https://stackoverflow.com/questions/27109701/aliasing-of-otherwise-equivalent-signed-and-unsigned-types // Especially comments by Columbo regarding N3797 and [conv.lval] #if (defined(NTL_LONGLONG_SP_MULMOD)) #if (NTL_BITS_PER_LONG >= NTL_SP_NBITS+4) static inline unsigned long sp_NormalizedLazyPrepMulModPreconWithRem(unsigned long& rres, long b, long n, unsigned long ninv) { unsigned long H = cast_unsigned(b); unsigned long Q = ll_mul_hi(H << 4, ninv); unsigned long L = cast_unsigned(b) << (NTL_SP_NBITS+2); long r = L - Q*cast_unsigned(n); // r in [0..2*n) r = sp_CorrectExcessQuo(Q, r, n); rres = r; return Q; // NOTE: not shifted } static inline unsigned long sp_NormalizedLazyPrepMulModPrecon(long b, long n, unsigned long ninv) { unsigned long H = cast_unsigned(b); unsigned long Q = ll_mul_hi(H << 4, ninv); unsigned long L = cast_unsigned(b) << (NTL_SP_NBITS+2); long r = L - Q*cast_unsigned(n); // r in [0..2*n) Q += 1L + sp_SignMask(r-n); return Q; // NOTE: not shifted } #else // NTL_BITS_PER_LONG == NTL_SP_NBITS+2 static inline unsigned long sp_NormalizedLazyPrepMulModPreconWithRem(unsigned long& rres, long b, long n, unsigned long ninv) { unsigned long H = cast_unsigned(b) << 2; unsigned long Q = ll_mul_hi(H, (ninv << 1)) + H; unsigned long rr = -Q*cast_unsigned(n); // r in [0..3*n) long r = sp_CorrectExcessQuo(Q, rr, n); r = sp_CorrectExcessQuo(Q, r, n); rres = r; return Q; // NOTE: not shifted } static inline unsigned long sp_NormalizedLazyPrepMulModPrecon(long b, long n, unsigned long ninv) { unsigned long H = cast_unsigned(b) << 2; unsigned long Q = ll_mul_hi(H, (ninv << 1)) + H; unsigned long rr = -Q*cast_unsigned(n); // r in [0..3*n) Q += 2L + sp_SignMask(rr-n) + sp_SignMask(rr-2*n); return Q; // NOTE: not shifted } #endif static inline unsigned long LazyPrepMulModPrecon(long b, long n, sp_inverse ninv) { return sp_NormalizedLazyPrepMulModPrecon(b << ninv.shamt, n << ninv.shamt, ninv.inv) << (NTL_BITS_PER_LONG-NTL_SP_NBITS-2); } static inline unsigned long LazyPrepMulModPreconWithRem(unsigned long& rres, long b, long n, sp_inverse ninv) { unsigned long qq, rr; qq = sp_NormalizedLazyPrepMulModPreconWithRem(rr, b << ninv.shamt, n << ninv.shamt, ninv.inv); rres = rr >> ninv.shamt; return qq << (NTL_BITS_PER_LONG-NTL_SP_NBITS-2); } #elif (NTL_BITS_PER_LONG - NTL_SP_NBITS >= 4 && NTL_WIDE_DOUBLE_PRECISION - NTL_SP_NBITS >= 4) // slightly faster functions, which should kick in on x86-64, where // NTL_BITS_PER_LONG == 64 // NTL_SP_NBITS == 60 (another reason for holding this back to 60 bits) // NTL_WIDE_DOUBLE_PRECISION == 64 // DIRT: if the relative error in floating point calcuations (muls and reciprocals) // is <= epsilon, the relative error in the calculations is <= 3*epsilon + // O(epsilon^2), and we require that this relative error is at most // 2^{-(NTL_SP_NBITS+2)}, so it should be pretty safe as long as // epsilon is at most, or not much geater than, 2^{-NTL_WIDE_DOUBLE_PRECISION}. static inline unsigned long LazyPrepMulModPrecon(long b, long n, wide_double ninv) { long q = (long) ( (((wide_double) b) * wide_double(4*NTL_SP_BOUND)) * ninv ); unsigned long rr = (cast_unsigned(b) << (NTL_SP_NBITS+2)) - cast_unsigned(q)*cast_unsigned(n); q += sp_SignMask(rr) + sp_SignMask(rr-n) + 1L; return cast_unsigned(q) << (NTL_BITS_PER_LONG - NTL_SP_NBITS - 2); } static inline unsigned long LazyPrepMulModPreconWithRem(unsigned long& rres, long b, long n, wide_double ninv) { long q = (long) ( (((wide_double) b) * wide_double(4*NTL_SP_BOUND)) * ninv ); unsigned long rr = (cast_unsigned(b) << (NTL_SP_NBITS+2)) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficitQuo(q, rr, n); r = sp_CorrectExcessQuo(q, r, n); unsigned long qres = cast_unsigned(q) << (NTL_BITS_PER_LONG - NTL_SP_NBITS - 2); rres = r; return qres; } #else static inline unsigned long LazyPrepMulModPrecon(long b, long n, wide_double ninv) { long q = (long) ( (((wide_double) b) * wide_double(NTL_SP_BOUND)) * ninv ); unsigned long rr = (cast_unsigned(b) << (NTL_SP_NBITS)) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficitQuo(q, rr, n); r = sp_CorrectExcessQuo(q, r, n); unsigned long qq = q; qq = 2*qq; r = 2*r; r = sp_CorrectExcessQuo(qq, r, n); qq = 2*qq; r = 2*r; qq += sp_SignMask(r-n) + 1L; return qq << (NTL_BITS_PER_LONG - NTL_SP_NBITS - 2); } static inline unsigned long LazyPrepMulModPreconWithRem(unsigned long& rres, long b, long n, wide_double ninv) { long q = (long) ( (((wide_double) b) * wide_double(NTL_SP_BOUND)) * ninv ); unsigned long rr = (cast_unsigned(b) << (NTL_SP_NBITS)) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficitQuo(q, rr, n); r = sp_CorrectExcessQuo(q, r, n); unsigned long qq = q; qq = 2*qq; r = 2*r; r = sp_CorrectExcessQuo(qq, r, n); qq = 2*qq; r = 2*r; r = sp_CorrectExcessQuo(qq, r, n); rres = r; return qq << (NTL_BITS_PER_LONG - NTL_SP_NBITS - 2); } #endif static inline unsigned long LazyMulModPreconQuo(unsigned long a, unsigned long b, unsigned long n, unsigned long bninv) { unsigned long q = ll_mul_hi(a, bninv); unsigned long r = a*b - q*n; q += sp_SignMask(r-n) + 1L; return q << (NTL_BITS_PER_LONG - NTL_SP_NBITS - 2); } static inline unsigned long LazyMulModPrecon(unsigned long a, unsigned long b, unsigned long n, unsigned long bninv) { unsigned long q = ll_mul_hi(a, bninv); unsigned long res = a*b - q*n; return res; } typedef long mint_t; typedef unsigned long umint_t; // For readability and to make it easier to adapt this // code to other settings static inline umint_t LazyReduce1(umint_t a, mint_t q) { return sp_CorrectExcess(mint_t(a), q); } static inline umint_t LazyReduce2(umint_t a, mint_t q) { return sp_CorrectExcess(a, 2*q); } // inputs in [0, 2*n), output in [0, 4*n) static inline umint_t LazyAddMod(umint_t a, umint_t b, mint_t n) { return a+b; } // inputs in [0, 2*n), output in [0, 4*n) static inline umint_t LazySubMod(umint_t a, umint_t b, mint_t n) { return a-b+2*n; } // inputs in [0, 2*n), output in [0, 2*n) static inline umint_t LazyAddMod2(umint_t a, umint_t b, mint_t n) { umint_t r = a+b; return sp_CorrectExcess(r, 2*n); } // inputs in [0, 2*n), output in [0, 2*n) static inline umint_t LazySubMod2(umint_t a, umint_t b, mint_t n) { umint_t r = a-b; return sp_CorrectDeficit(r, 2*n); } #ifdef NTL_AVOID_BRANCHING // x, y in [0, 4*m) // returns x + y mod 4*m, in [0, 4*m) inline static umint_t LazyAddMod4(umint_t x, umint_t y, mint_t m) { x = LazyReduce2(x, m); y = LazyReduce2(y, m); return x+y; } // x, y in [0, 4*m) // returns x - y mod 4*m, in [0, 4*m) inline static umint_t LazySubMod4(umint_t x, umint_t y, mint_t m) { x = LazyReduce2(x, m); y = LazyReduce2(y, m); return x-y+2*m; } #else static inline umint_t LazyAddMod4(umint_t x, umint_t y, umint_t m) { y = 4*m - y; umint_t z = x - y; z += (x < y) ? 4*m : 0; return z; } static inline umint_t LazySubMod4(umint_t x, umint_t y, umint_t m) { umint_t z = x - y; z += (x < y) ? 4*m : 0; return z; } #endif // Input and output in [0, 4*n) static inline umint_t LazyDoubleMod4(umint_t a, mint_t n) { return 2 * LazyReduce2(a, n); } // Input and output in [0, 2*n) static inline umint_t LazyDoubleMod2(umint_t a, mint_t n) { return 2 * LazyReduce1(a, n); } void ComputeMultipliers(Vec& v, long k, mint_t q, mulmod_t qinv, const mint_t* root) { long old_len = v.length(); v.SetLength(k+1); for (long s = max(old_len, 1); s <= k; s++) { v[s].wtab_precomp.SetLength(1L << (s-1)); v[s].wqinvtab_precomp.SetLength(1L << (s-1)); } if (k >= 1) { v[1].wtab_precomp[0] = 1; v[1].wqinvtab_precomp[0] = LazyPrepMulModPrecon(1, q, qinv); } if (k >= 2) { v[2].wtab_precomp[0] = v[1].wtab_precomp[0]; v[2].wtab_precomp[1] = root[2]; v[2].wqinvtab_precomp[0] = v[1].wqinvtab_precomp[0]; v[2].wqinvtab_precomp[1] = LazyPrepMulModPrecon(root[2], q, qinv); } for (long s = 3; s <= k; s++) { long m = 1L << s; long m_half = 1L << (s-1); long m_fourth = 1L << (s-2); mint_t* NTL_RESTRICT wtab = v[s].wtab_precomp.elts(); mint_t* NTL_RESTRICT wtab1 = v[s-1].wtab_precomp.elts(); mulmod_precon_t* NTL_RESTRICT wqinvtab = v[s].wqinvtab_precomp.elts(); mulmod_precon_t* NTL_RESTRICT wqinvtab1 = v[s-1].wqinvtab_precomp.elts(); mint_t w = root[s]; umint_t wqinv_rem; mulmod_precon_t wqinv = LazyPrepMulModPreconWithRem(wqinv_rem, w, q, qinv); for (long i = m_half-1, j = m_fourth-1; i >= 0; i -= 2, j--) { mint_t w_j = wtab1[j]; mulmod_precon_t wqi_j = wqinvtab1[j]; #if 0 mint_t w_i = LazyReduce1(LazyMulModPrecon(w_j, w, q, wqinv), q); mulmod_precon_t wqi_i = LazyMulModPreconQuo(wqinv_rem, w_j, q, wqi_j) + cast_unsigned(w_j)*wqinv; #else // This code sequence makes sure the compiler sees // that the product w_j*wqinv needs to be computed just once ll_type x; ll_mul(x, w_j, wqinv); umint_t hi = ll_get_hi(x); umint_t lo = ll_get_lo(x); umint_t r = cast_unsigned(w_j)*cast_unsigned(w) - hi*cast_unsigned(q); mint_t w_i = LazyReduce1(r, q); mulmod_precon_t wqi_i = lo+LazyMulModPreconQuo(wqinv_rem, w_j, q, wqi_j); #endif wtab[i-1] = w_j; wqinvtab[i-1] = wqi_j; wtab[i] = w_i; wqinvtab[i] = wqi_i; } } #if 0 // verify result for (long s = 1; s <= k; s++) { mint_t *wtab = v[s].wtab_precomp.elts(); mulmod_precon_t *wqinvtab = v[s].wqinvtab_precomp.elts(); long m_half = 1L << (s-1); mint_t w = root[s]; mint_t w_i = 1; for (long i = 0; i < m_half; i++) { if (wtab[i] != w_i || wqinvtab[i] != LazyPrepMulModPrecon(w_i, q, qinv)) Error("bad table entry"); w_i = MulMod(w_i, w, q, qinv); } } #endif } #else // Hacks to make the LAZY code work with ordinary modular arithmetic typedef long mint_t; typedef long umint_t; static inline mint_t IdentityMod(mint_t a, mint_t q) { return a; } static inline mint_t DoubleMod(mint_t a, mint_t q) { return AddMod(a, a, q); } #define LazyPrepMulModPrecon PrepMulModPrecon #define LazyMulModPrecon MulModPrecon #define LazyReduce1 IdentityMod #define LazyReduce2 IdentityMod #define LazyAddMod AddMod #define LazySubMod SubMod #define LazyAddMod2 AddMod #define LazySubMod2 SubMod #define LazyAddMod4 AddMod #define LazySubMod4 SubMod #define LazyDoubleMod2 DoubleMod #define LazyDoubleMod4 DoubleMod void ComputeMultipliers(Vec& v, long k, mint_t q, mulmod_t qinv, const mint_t* root) { long old_len = v.length(); v.SetLength(k+1); for (long s = max(old_len, 1); s <= k; s++) { v[s].wtab_precomp.SetLength(1L << (s-1)); v[s].wqinvtab_precomp.SetLength(1L << (s-1)); } if (k >= 1) { v[1].wtab_precomp[0] = 1; v[1].wqinvtab_precomp[0] = PrepMulModPrecon(1, q, qinv); } if (k >= 2) { v[2].wtab_precomp[0] = v[1].wtab_precomp[0]; v[2].wtab_precomp[1] = root[2]; v[2].wqinvtab_precomp[0] = v[1].wqinvtab_precomp[0]; v[2].wqinvtab_precomp[1] = PrepMulModPrecon(root[2], q, qinv); } for (long s = 3; s <= k; s++) { long m = 1L << s; long m_half = 1L << (s-1); long m_fourth = 1L << (s-2); mint_t* NTL_RESTRICT wtab = v[s].wtab_precomp.elts(); mint_t* NTL_RESTRICT wtab1 = v[s-1].wtab_precomp.elts(); mulmod_precon_t* NTL_RESTRICT wqinvtab = v[s].wqinvtab_precomp.elts(); mulmod_precon_t* NTL_RESTRICT wqinvtab1 = v[s-1].wqinvtab_precomp.elts(); mint_t w = root[s]; mulmod_precon_t wqinv = PrepMulModPrecon(w, q, qinv); for (long i = m_half-1, j = m_fourth-1; i >= 0; i -= 2, j--) { mint_t w_j = wtab1[j]; mulmod_precon_t wqi_j = wqinvtab1[j]; mint_t w_i = MulModPrecon(w_j, w, q, wqinv); mulmod_precon_t wqi_i = PrepMulModPrecon(w_i, q, qinv); wtab[i-1] = w_j; wqinvtab[i-1] = wqi_j; wtab[i] = w_i; wqinvtab[i] = wqi_i; } } #if 0 // verify result for (long s = 1; s <= k; s++) { mint_t *wtab = v[s].wtab_precomp.elts(); mulmod_precon_t *wqinvtab = v[s].wqinvtab_precomp.elts(); long m_half = 1L << (s-1); mint_t w = root[s]; mint_t w_i = 1; for (long i = 0; i < m_half; i++) { if (wtab[i] != w_i || wqinvtab[i] != PrepMulModPrecon(w_i, q, qinv)) Error("bad table entry"); w_i = MulMod(w_i, w, q, qinv); } } #endif } #endif static void LazyPrecompFFTMultipliers(long k, mint_t q, mulmod_t qinv, const mint_t *root, const FFTMultipliers& tab) { if (k < 1) LogicError("LazyPrecompFFTMultipliers: bad input"); do { // NOTE: thread safe lazy init FFTMultipliers::Builder bld(tab, k+1); long amt = bld.amt(); if (!amt) break; long first = k+1-amt; // initialize entries first..k for (long s = first; s <= k; s++) { UniquePtr item; if (s == 0) { bld.move(item); // position 0 not used continue; } if (s == 1) { item.make(); item->wtab_precomp.SetLength(1); item->wqinvtab_precomp.SetLength(1); item->wtab_precomp[0] = 1; item->wqinvtab_precomp[0] = LazyPrepMulModPrecon(1, q, qinv); bld.move(item); continue; } item.make(); item->wtab_precomp.SetLength(1L << (s-1)); item->wqinvtab_precomp.SetLength(1L << (s-1)); long m = 1L << s; long m_half = 1L << (s-1); long m_fourth = 1L << (s-2); const mint_t *wtab_last = tab[s-1]->wtab_precomp.elts(); const mulmod_precon_t *wqinvtab_last = tab[s-1]->wqinvtab_precomp.elts(); mint_t *wtab = item->wtab_precomp.elts(); mulmod_precon_t *wqinvtab = item->wqinvtab_precomp.elts(); for (long i = 0; i < m_fourth; i++) { wtab[i] = wtab_last[i]; wqinvtab[i] = wqinvtab_last[i]; } mint_t w = root[s]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, qinv); // prepare wtab... if (s == 2) { wtab[1] = LazyReduce1(LazyMulModPrecon(wtab[0], w, q, wqinv), q); wqinvtab[1] = LazyPrepMulModPrecon(wtab[1], q, qinv); } else { long i, j; i = m_half-1; j = m_fourth-1; wtab[i-1] = wtab[j]; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = LazyReduce1(LazyMulModPrecon(wtab[i-1], w, q, wqinv), q); i -= 2; j --; for (; i >= 0; i -= 2, j --) { mint_t wp2 = wtab[i+2]; mint_t wm1 = wtab[j]; wqinvtab[i+2] = LazyPrepMulModPrecon(wp2, q, qinv); wtab[i-1] = wm1; wqinvtab[i-1] = wqinvtab[j]; wtab[i] = LazyReduce1(LazyMulModPrecon(wm1, w, q, wqinv), q); } wqinvtab[1] = LazyPrepMulModPrecon(wtab[1], q, qinv); } bld.move(item); } } while (0); } //=================================================================== // TRUNCATED FFT // This code is derived from code originally developed // by David Harvey. I include his original documentation, // annotated appropriately to highlight differences in // the implemebtation (see NOTEs). /* The DFT is defined as follows. Let the input sequence be a_0, ..., a_{N-1}. Let w = standard primitive N-th root of 1, i.e. w = g^(2^FFT62_MAX_LGN / N), where g = some fixed element of Z/pZ of order 2^FFT62_MAX_LGN. Let Z = an element of (Z/pZ)^* (twisting parameter). Then the output sequence is b_j = \sum_{0 <= i < N} Z^i a_i w^(ij'), for 0 <= j < N, where j' is the length-lgN bit-reversal of j. Some of the FFT routines can operate on truncated sequences of certain "admissible" sizes. A size parameter n is admissible if 1 <= n <= N, and n is divisible by a certain power of 2. The precise power depends on the recursive array decomposition of the FFT. The smallest admissible n' >= n can be obtained via fft62_next_size(). */ // NOTE: the twising parameter is not implemented. // NOTE: the next admissible size function is called FFTRoundUp, // and is defined in FFT.h. /* Truncated FFT interface is as follows: xn and yn must be admissible sizes for N. Input in xp[] is a_0, a_1, ..., a_{xn-1}. Assumes a_i = 0 for xn <= i < N. Output in yp[] is b_0, ..., b_{yn-1}, i.e. only first yn outputs are computed. Twisting parameter Z is described by z and lgH. If z == 0, then Z = basic 2^lgH-th root of 1, and must have lgH >= lgN + 1. If z != 0, then Z = z (and lgH is ignored). The buffers {xp,xn} and {yp,yn} may overlap, but only if xp == yp. Inputs are in [0, 2p), outputs are in [0, 2p). threads = number of OpenMP threads to use. */ /* Inverse truncated FFT interface is as follows. xn and yn must be admissible sizes for N, with yn <= xn. Input in xp[] is b_0, b_1, ..., b_{yn-1}, N*a_{yn}, ..., N*a_{xn-1}. Assumes a_i = 0 for xn <= i < N. Output in yp[] is N*a_0, ..., N*a_{yn-1}. Twisting parameter Z is described by z and lgH. If z == 0, then Z = basic 2^lgH-th root of 1, and must have lgH >= lgN + 1. If z != 0, then Z = z^(-1) (and lgH is ignored). The buffers {xp,xn} and {yp,yn} may overlap, but only if xp == yp. Inputs are in [0, 4p), outputs are in [0, 4p). threads = number of OpenMP threads to use. (note: no function actually implements this interface in full generality! This is because it is tricky (and not that useful) to implement the twisting parameter when xn != yn.) */ // NOTE: threads and twisting parameter are not used here. // NOTE: the code has been re-written and simplified so that // everything is done in place, so xp == yp. //=================================================================== // NOTE: these could be inlined, but I found the code generation // to be extremely sensitive to seemingly trivial changes, // so it seems safest to use macros instead. // w and wqinv are read only once. // q is read several times. // xx0, xx1 are read once and written once #define fwd_butterfly(xx0, xx1, w, q, wqinv) \ do \ { \ umint_t x0_ = xx0; \ umint_t x1_ = xx1; \ umint_t t_ = LazySubMod(x0_, x1_, q); \ xx0 = LazyAddMod2(x0_, x1_, q); \ xx1 = LazyMulModPrecon(t_, w, q, wqinv); \ } \ while (0) #define fwd_butterfly_neg(xx0, xx1, w, q, wqinv) \ do \ { \ umint_t x0_ = xx0; \ umint_t x1_ = xx1; \ umint_t t_ = LazySubMod(x1_, x0_, q); /* NEG */ \ xx0 = LazyAddMod2(x0_, x1_, q); \ xx1 = LazyMulModPrecon(t_, w, q, wqinv); \ } \ while (0) #define fwd_butterfly1(xx0, xx1, w, q, wqinv, w1, w1qinv) \ do \ { \ umint_t x0_ = xx0; \ umint_t x1_ = xx1; \ umint_t t_ = LazySubMod(x0_, x1_, q); \ xx0 = LazyAddMod2(x0_, x1_, q); \ xx1 = LazyMulModPrecon(LazyMulModPrecon(t_, w1, q, w1qinv), w, q, wqinv); \ } \ while (0) #define fwd_butterfly0(xx0, xx1, q) \ do \ { \ umint_t x0_ = xx0; \ umint_t x1_ = xx1; \ xx0 = LazyAddMod2(x0_, x1_, q); \ xx1 = LazySubMod2(x0_, x1_, q); \ } \ while (0) #define NTL_NEW_FFT_THRESH (11) struct new_mod_t { mint_t q; const mint_t **wtab; const mulmod_precon_t **wqinvtab; }; // requires size divisible by 8 static void new_fft_layer(umint_t* xp, long blocks, long size, const mint_t* NTL_RESTRICT wtab, const mulmod_precon_t* NTL_RESTRICT wqinvtab, mint_t q) { size /= 2; do { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + size; // first 4 butterflies fwd_butterfly0(xp0[0+0], xp1[0+0], q); fwd_butterfly(xp0[0+1], xp1[0+1], wtab[0+1], q, wqinvtab[0+1]); fwd_butterfly(xp0[0+2], xp1[0+2], wtab[0+2], q, wqinvtab[0+2]); fwd_butterfly(xp0[0+3], xp1[0+3], wtab[0+3], q, wqinvtab[0+3]); // 4-way unroll for (long j = 4; j < size; j += 4) { fwd_butterfly(xp0[j+0], xp1[j+0], wtab[j+0], q, wqinvtab[j+0]); fwd_butterfly(xp0[j+1], xp1[j+1], wtab[j+1], q, wqinvtab[j+1]); fwd_butterfly(xp0[j+2], xp1[j+2], wtab[j+2], q, wqinvtab[j+2]); fwd_butterfly(xp0[j+3], xp1[j+3], wtab[j+3], q, wqinvtab[j+3]); } xp += 2 * size; } while (--blocks != 0); } static void new_fft_last_two_layers(umint_t* xp, long blocks, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { // 4th root of unity mint_t w = wtab[1]; mulmod_precon_t wqinv = wqinvtab[1]; do { umint_t u0 = xp[0]; umint_t u1 = xp[1]; umint_t u2 = xp[2]; umint_t u3 = xp[3]; umint_t v0 = LazyAddMod2(u0, u2, q); umint_t v2 = LazySubMod2(u0, u2, q); umint_t v1 = LazyAddMod2(u1, u3, q); umint_t t = LazySubMod(u1, u3, q); umint_t v3 = LazyMulModPrecon(t, w, q, wqinv); xp[0] = LazyAddMod2(v0, v1, q); xp[1] = LazySubMod2(v0, v1, q); xp[2] = LazyAddMod2(v2, v3, q); xp[3] = LazySubMod2(v2, v3, q); xp += 4; } while (--blocks != 0); } void new_fft_base(umint_t* xp, long lgN, const new_mod_t& mod) { if (lgN == 0) return; mint_t q = mod.q; if (lgN == 1) { umint_t x0 = xp[0]; umint_t x1 = xp[1]; xp[0] = LazyAddMod2(x0, x1, q); xp[1] = LazySubMod2(x0, x1, q); return; } const mint_t** wtab = mod.wtab; const mulmod_precon_t** wqinvtab = mod.wqinvtab; long N = 1L << lgN; for (long j = lgN, size = N, blocks = 1; j > 2; j--, blocks <<= 1, size >>= 1) new_fft_layer(xp, blocks, size, wtab[j], wqinvtab[j], q); new_fft_last_two_layers(xp, N/4, wtab[2], wqinvtab[2], q); } // Implements the truncated FFT interface, described above. // All computations done in place, and xp should point to // an array of size N, all of which may be overwitten // during the computation. static void new_fft_short(umint_t* xp, long yn, long xn, long lgN, const new_mod_t& mod) { long N = 1L << lgN; if (yn == N) { if (xn == N && lgN <= NTL_NEW_FFT_THRESH) { // no truncation new_fft_base(xp, lgN, mod); return; } } // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; if (yn <= half) { if (xn <= half) { new_fft_short(xp, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> X + Y for (long j = 0; j < xn; j++) xp[j] = LazyAddMod2(xp[j], xp[j + half], q); new_fft_short(xp, yn, half, lgN - 1, mod); } } else { yn -= half; umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN]; if (xn <= half) { // X -> (X, w*X) for (long j = 0; j < xn; j++) xp1[j] = LazyMulModPrecon(xp0[j], wtab[j], q, wqinvtab[j]); new_fft_short(xp0, half, xn, lgN - 1, mod); new_fft_short(xp1, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> (X + Y, w*(X - Y)) // DIRT: assumes xn is a multiple of 4 fwd_butterfly0(xp0[0], xp1[0], q); fwd_butterfly(xp0[1], xp1[1], wtab[1], q, wqinvtab[1]); fwd_butterfly(xp0[2], xp1[2], wtab[2], q, wqinvtab[2]); fwd_butterfly(xp0[3], xp1[3], wtab[3], q, wqinvtab[3]); for (long j = 4; j < xn; j+=4) { fwd_butterfly(xp0[j+0], xp1[j+0], wtab[j+0], q, wqinvtab[j+0]); fwd_butterfly(xp0[j+1], xp1[j+1], wtab[j+1], q, wqinvtab[j+1]); fwd_butterfly(xp0[j+2], xp1[j+2], wtab[j+2], q, wqinvtab[j+2]); fwd_butterfly(xp0[j+3], xp1[j+3], wtab[j+3], q, wqinvtab[j+3]); } // X -> (X, w*X) for (long j = xn; j < half; j++) xp1[j] = LazyMulModPrecon(xp0[j], wtab[j], q, wqinvtab[j]); new_fft_short(xp0, half, half, lgN - 1, mod); new_fft_short(xp1, yn, half, lgN - 1, mod); } } } static void new_fft_short_notab(umint_t* xp, long yn, long xn, long lgN, const new_mod_t& mod, mint_t w, mulmod_precon_t wqinv) // This version assumes that we only have tables up to level lgN-1, // and w generates the values at level lgN. // DIRT: requires xn even { long N = 1L << lgN; // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; if (yn <= half) { if (xn <= half) { new_fft_short(xp, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> X + Y for (long j = 0; j < xn; j++) xp[j] = LazyAddMod2(xp[j], xp[j + half], q); new_fft_short(xp, yn, half, lgN - 1, mod); } } else { yn -= half; umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN-1]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN-1]; if (xn <= half) { // X -> (X, w*X) for (long j = 0, j_half = 0; j < xn; j+=2, j_half++) { xp1[j] = LazyMulModPrecon(xp0[j], wtab[j_half], q, wqinvtab[j_half]); xp1[j+1] = LazyMulModPrecon(LazyMulModPrecon(xp0[j+1], w, q, wqinv), wtab[j_half], q, wqinvtab[j_half]); } new_fft_short(xp0, half, xn, lgN - 1, mod); new_fft_short(xp1, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> (X + Y, w*(X - Y)) fwd_butterfly0(xp0[0], xp1[0], q); fwd_butterfly(xp0[1], xp1[1], w, q, wqinv); long j = 2; long j_half = 1; for (; j < xn; j+=2, j_half++) { fwd_butterfly(xp0[j], xp1[j], wtab[j_half], q, wqinvtab[j_half]); fwd_butterfly1(xp0[j+1], xp1[j+1], wtab[j_half], q, wqinvtab[j_half], w, wqinv); } // X -> (X, w*X) for (; j < half; j+=2, j_half++) { xp1[j] = LazyMulModPrecon(xp0[j], wtab[j_half], q, wqinvtab[j_half]); xp1[j+1] = LazyMulModPrecon(LazyMulModPrecon(xp0[j+1], w, q, wqinv), wtab[j_half], q, wqinvtab[j_half]); } new_fft_short(xp0, half, half, lgN - 1, mod); new_fft_short(xp1, yn, half, lgN - 1, mod); } } } //===== // NOTE: these "flipped" routines perform the same // functions as their normal, "unflipped" counter-parts, // except that they work with inverted roots. // They also perform no truncation, just to keep things simple. // All of this is necessary only to implement the UpdateMap // routines for ZZ_pX and zz_pX. // requires size divisible by 8 static void new_fft_layer_flipped(umint_t* xp, long blocks, long size, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { size /= 2; const mint_t* NTL_RESTRICT wtab1 = wtab + size; const mulmod_precon_t* NTL_RESTRICT wqinvtab1 = wqinvtab + size; do { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + size; // first 4 butterflies fwd_butterfly0(xp0[0+0], xp1[0+0], q); fwd_butterfly_neg(xp0[0+1], xp1[0+1], wtab1[-(0+1)], q, wqinvtab1[-(0+1)]); fwd_butterfly_neg(xp0[0+2], xp1[0+2], wtab1[-(0+2)], q, wqinvtab1[-(0+2)]); fwd_butterfly_neg(xp0[0+3], xp1[0+3], wtab1[-(0+3)], q, wqinvtab1[-(0+3)]); // 4-way unroll for (long j = 4; j < size; j += 4) { fwd_butterfly_neg(xp0[j+0], xp1[j+0], wtab1[-(j+0)], q, wqinvtab1[-(j+0)]); fwd_butterfly_neg(xp0[j+1], xp1[j+1], wtab1[-(j+1)], q, wqinvtab1[-(j+1)]); fwd_butterfly_neg(xp0[j+2], xp1[j+2], wtab1[-(j+2)], q, wqinvtab1[-(j+2)]); fwd_butterfly_neg(xp0[j+3], xp1[j+3], wtab1[-(j+3)], q, wqinvtab1[-(j+3)]); } xp += 2 * size; } while (--blocks != 0); } static void new_fft_last_two_layers_flipped(umint_t* xp, long blocks, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { // 4th root of unity mint_t w = wtab[1]; mulmod_precon_t wqinv = wqinvtab[1]; do { umint_t u0 = xp[0]; umint_t u1 = xp[1]; umint_t u2 = xp[2]; umint_t u3 = xp[3]; umint_t v0 = LazyAddMod2(u0, u2, q); umint_t v2 = LazySubMod2(u0, u2, q); umint_t v1 = LazyAddMod2(u1, u3, q); umint_t t = LazySubMod(u3, u1, q); // NEG umint_t v3 = LazyMulModPrecon(t, w, q, wqinv); xp[0] = LazyAddMod2(v0, v1, q); xp[1] = LazySubMod2(v0, v1, q); xp[2] = LazyAddMod2(v2, v3, q); xp[3] = LazySubMod2(v2, v3, q); xp += 4; } while (--blocks != 0); } void new_fft_base_flipped(umint_t* xp, long lgN, const new_mod_t& mod) { if (lgN == 0) return; mint_t q = mod.q; if (lgN == 1) { umint_t x0 = xp[0]; umint_t x1 = xp[1]; xp[0] = LazyAddMod2(x0, x1, q); xp[1] = LazySubMod2(x0, x1, q); return; } const mint_t** wtab = mod.wtab; const mulmod_precon_t** wqinvtab = mod.wqinvtab; long N = 1L << lgN; for (long j = lgN, size = N, blocks = 1; j > 2; j--, blocks <<= 1, size >>= 1) new_fft_layer_flipped(xp, blocks, size, wtab[j], wqinvtab[j], q); new_fft_last_two_layers_flipped(xp, N/4, wtab[2], wqinvtab[2], q); } static void new_fft_short_flipped(umint_t* xp, long lgN, const new_mod_t& mod) { long N = 1L << lgN; if (lgN <= NTL_NEW_FFT_THRESH) { new_fft_base_flipped(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN] + half; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN] + half; // (X, Y) -> (X + Y, w*(X - Y)) fwd_butterfly0(xp0[0], xp1[0], q); fwd_butterfly_neg(xp0[1], xp1[1], wtab[-1], q, wqinvtab[-1]); fwd_butterfly_neg(xp0[2], xp1[2], wtab[-2], q, wqinvtab[-2]); fwd_butterfly_neg(xp0[3], xp1[3], wtab[-3], q, wqinvtab[-3]); for (long j = 4; j < half; j+=4) { fwd_butterfly_neg(xp0[j+0], xp1[j+0], wtab[-(j+0)], q, wqinvtab[-(j+0)]); fwd_butterfly_neg(xp0[j+1], xp1[j+1], wtab[-(j+1)], q, wqinvtab[-(j+1)]); fwd_butterfly_neg(xp0[j+2], xp1[j+2], wtab[-(j+2)], q, wqinvtab[-(j+2)]); fwd_butterfly_neg(xp0[j+3], xp1[j+3], wtab[-(j+3)], q, wqinvtab[-(j+3)]); } new_fft_short_flipped(xp0, lgN - 1, mod); new_fft_short_flipped(xp1, lgN - 1, mod); } // IFFT (inverse truncated FFT) #define inv_butterfly0(xx0, xx1, q) \ do \ { \ umint_t x0_ = LazyReduce2(xx0, q); \ umint_t x1_ = LazyReduce2(xx1, q); \ xx0 = LazyAddMod(x0_, x1_, q); \ xx1 = LazySubMod(x0_, x1_, q); \ } while (0) #define inv_butterfly_neg(xx0, xx1, w, q, wqinv) \ do \ { \ umint_t x0_ = LazyReduce2(xx0, q); \ umint_t x1_ = xx1; \ umint_t t_ = LazyMulModPrecon(x1_, w, q, wqinv); \ xx0 = LazySubMod(x0_, t_, q); /* NEG */ \ xx1 = LazyAddMod(x0_, t_, q); /* NEG */ \ } while (0) #define inv_butterfly(xx0, xx1, w, q, wqinv) \ do \ { \ umint_t x0_ = LazyReduce2(xx0, q); \ umint_t x1_ = xx1; \ umint_t t_ = LazyMulModPrecon(x1_, w, q, wqinv); \ xx0 = LazyAddMod(x0_, t_, q); \ xx1 = LazySubMod(x0_, t_, q); \ } while (0) #define inv_butterfly1_neg(xx0, xx1, w, q, wqinv, w1, w1qinv) \ do \ { \ umint_t x0_ = LazyReduce2(xx0, q); \ umint_t x1_ = xx1; \ umint_t t_ = LazyMulModPrecon(LazyMulModPrecon(x1_, w1, q, w1qinv), w, q, wqinv); \ xx0 = LazySubMod(x0_, t_, q); /* NEG */ \ xx1 = LazyAddMod(x0_, t_, q); /* NEG */ \ } while (0) static void new_ifft_short2(umint_t* yp, long yn, long lgN, const new_mod_t& mod); // requires size divisible by 8 static void new_ifft_layer(umint_t* xp, long blocks, long size, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { size /= 2; const mint_t* NTL_RESTRICT wtab1 = wtab + size; const mulmod_precon_t* NTL_RESTRICT wqinvtab1 = wqinvtab + size; do { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + size; // first 4 butterflies inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly_neg(xp0[1], xp1[1], wtab1[-1], q, wqinvtab1[-1]); inv_butterfly_neg(xp0[2], xp1[2], wtab1[-2], q, wqinvtab1[-2]); inv_butterfly_neg(xp0[3], xp1[3], wtab1[-3], q, wqinvtab1[-3]); // 4-way unroll for (long j = 4; j < size; j+= 4) { inv_butterfly_neg(xp0[j+0], xp1[j+0], wtab1[-(j+0)], q, wqinvtab1[-(j+0)]); inv_butterfly_neg(xp0[j+1], xp1[j+1], wtab1[-(j+1)], q, wqinvtab1[-(j+1)]); inv_butterfly_neg(xp0[j+2], xp1[j+2], wtab1[-(j+2)], q, wqinvtab1[-(j+2)]); inv_butterfly_neg(xp0[j+3], xp1[j+3], wtab1[-(j+3)], q, wqinvtab1[-(j+3)]); } xp += 2 * size; } while (--blocks != 0); } static void new_ifft_first_two_layers(umint_t* xp, long blocks, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { // 4th root of unity mint_t w = wtab[1]; mulmod_precon_t wqinv = wqinvtab[1]; do { umint_t u0 = LazyReduce2(xp[0], q); umint_t u1 = LazyReduce2(xp[1], q); umint_t u2 = LazyReduce2(xp[2], q); umint_t u3 = LazyReduce2(xp[3], q); umint_t v0 = LazyAddMod2(u0, u1, q); umint_t v1 = LazySubMod2(u0, u1, q); umint_t v2 = LazyAddMod2(u2, u3, q); umint_t t = LazySubMod(u2, u3, q); umint_t v3 = LazyMulModPrecon(t, w, q, wqinv); xp[0] = LazyAddMod(v0, v2, q); xp[2] = LazySubMod(v0, v2, q); xp[1] = LazySubMod(v1, v3, q); // NEG xp[3] = LazyAddMod(v1, v3, q); // NEG xp += 4; } while (--blocks != 0); } static void new_ifft_base(umint_t* xp, long lgN, const new_mod_t& mod) { if (lgN == 0) return; mint_t q = mod.q; if (lgN == 1) { umint_t x0 = LazyReduce2(xp[0], q); umint_t x1 = LazyReduce2(xp[1], q); xp[0] = LazyAddMod(x0, x1, q); xp[1] = LazySubMod(x0, x1, q); return; } const mint_t** wtab = mod.wtab; const mulmod_precon_t** wqinvtab = mod.wqinvtab; long blocks = 1L << (lgN - 2); new_ifft_first_two_layers(xp, blocks, wtab[2], wqinvtab[2], q); blocks >>= 1; long size = 8; for (long j = 3; j <= lgN; j++, blocks >>= 1, size <<= 1) new_ifft_layer(xp, blocks, size, wtab[j], wqinvtab[j], q); } static void new_ifft_short1(umint_t* xp, long yn, long lgN, const new_mod_t& mod) // Implements truncated inverse FFT interface, but with xn==yn. // All computations are done in place. { long N = 1L << lgN; if (yn == N && lgN <= NTL_NEW_FFT_THRESH) { // no truncation new_ifft_base(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j++) xp[j] = LazyDoubleMod4(xp[j], q); new_ifft_short1(xp, yn, lgN - 1, mod); } else { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN]; new_ifft_short1(xp0, half, lgN - 1, mod); yn -= half; // X -> (2X, w*X) for (long j = yn; j < half; j++) { umint_t x0 = xp0[j]; xp0[j] = LazyDoubleMod4(x0, q); xp1[j] = LazyMulModPrecon(x0, wtab[j], q, wqinvtab[j]); } new_ifft_short2(xp1, yn, lgN - 1, mod); // (X, Y) -> (X + Y/w, X - Y/w) { const mint_t* NTL_RESTRICT wtab1 = wtab + half; const mulmod_precon_t* NTL_RESTRICT wqinvtab1 = wqinvtab + half; // DIRT: assumes yn is a multiple of 4 inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly_neg(xp0[1], xp1[1], wtab1[-1], q, wqinvtab1[-1]); inv_butterfly_neg(xp0[2], xp1[2], wtab1[-2], q, wqinvtab1[-2]); inv_butterfly_neg(xp0[3], xp1[3], wtab1[-3], q, wqinvtab1[-3]); for (long j = 4; j < yn; j+=4) { inv_butterfly_neg(xp0[j+0], xp1[j+0], wtab1[-(j+0)], q, wqinvtab1[-(j+0)]); inv_butterfly_neg(xp0[j+1], xp1[j+1], wtab1[-(j+1)], q, wqinvtab1[-(j+1)]); inv_butterfly_neg(xp0[j+2], xp1[j+2], wtab1[-(j+2)], q, wqinvtab1[-(j+2)]); inv_butterfly_neg(xp0[j+3], xp1[j+3], wtab1[-(j+3)], q, wqinvtab1[-(j+3)]); } } } } static void new_ifft_short1_notab(umint_t* xp, long yn, long lgN, const new_mod_t& mod, mint_t w, mulmod_precon_t wqinv, mint_t iw, mulmod_precon_t iwqinv) // This version assumes that we only have tables up to level lgN-1, // and w generates the values at level lgN. // DIRT: requires yn even { long N = 1L << lgN; // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j++) xp[j] = LazyDoubleMod4(xp[j], q); new_ifft_short1(xp, yn, lgN - 1, mod); } else { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN-1]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN-1]; new_ifft_short1(xp0, half, lgN - 1, mod); yn -= half; // X -> (2X, w*X) for (long j = yn, j_half = yn/2; j < half; j+=2, j_half++) { { umint_t x0 = xp0[j+0]; xp0[j+0] = LazyDoubleMod4(x0, q); xp1[j+0] = LazyMulModPrecon(x0, wtab[j_half], q, wqinvtab[j_half]); } { umint_t x0 = xp0[j+1]; xp0[j+1] = LazyDoubleMod4(x0, q); xp1[j+1] = LazyMulModPrecon(LazyMulModPrecon(x0, w, q, wqinv), wtab[j_half], q, wqinvtab[j_half]); } } new_ifft_short2(xp1, yn, lgN - 1, mod); // (X, Y) -> (X + Y/w, X - Y/w) { const mint_t* NTL_RESTRICT wtab1 = wtab + half/2; const mulmod_precon_t* NTL_RESTRICT wqinvtab1 = wqinvtab + half/2; inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly(xp0[1], xp1[1], iw, q, iwqinv); for (long j = 2, j_half = 1; j < yn; j+=2, j_half++) { inv_butterfly_neg(xp0[j+0], xp1[j+0], wtab1[-j_half], q, wqinvtab1[-j_half]); inv_butterfly1_neg(xp0[j+1], xp1[j+1], wtab1[-j_half], q, wqinvtab1[-j_half], iw, iwqinv); } } } } //========= // requires size divisible by 8 static void new_ifft_layer_flipped(umint_t* xp, long blocks, long size, const mint_t* NTL_RESTRICT wtab, const mulmod_precon_t* NTL_RESTRICT wqinvtab, mint_t q) { size /= 2; do { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + size; // first 4 butterflies inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly(xp0[1], xp1[1], wtab[1], q, wqinvtab[1]); inv_butterfly(xp0[2], xp1[2], wtab[2], q, wqinvtab[2]); inv_butterfly(xp0[3], xp1[3], wtab[3], q, wqinvtab[3]); // 4-way unroll for (long j = 4; j < size; j+= 4) { inv_butterfly(xp0[j+0], xp1[j+0], wtab[j+0], q, wqinvtab[j+0]); inv_butterfly(xp0[j+1], xp1[j+1], wtab[j+1], q, wqinvtab[j+1]); inv_butterfly(xp0[j+2], xp1[j+2], wtab[j+2], q, wqinvtab[j+2]); inv_butterfly(xp0[j+3], xp1[j+3], wtab[j+3], q, wqinvtab[j+3]); } xp += 2 * size; } while (--blocks != 0); } static void new_ifft_first_two_layers_flipped(umint_t* xp, long blocks, const mint_t* wtab, const mulmod_precon_t* wqinvtab, mint_t q) { // 4th root of unity mint_t w = wtab[1]; mulmod_precon_t wqinv = wqinvtab[1]; do { umint_t u0 = LazyReduce2(xp[0], q); umint_t u1 = LazyReduce2(xp[1], q); umint_t u2 = LazyReduce2(xp[2], q); umint_t u3 = LazyReduce2(xp[3], q); umint_t v0 = LazyAddMod2(u0, u1, q); umint_t v1 = LazySubMod2(u0, u1, q); umint_t v2 = LazyAddMod2(u2, u3, q); umint_t t = LazySubMod(u2, u3, q); umint_t v3 = LazyMulModPrecon(t, w, q, wqinv); xp[0] = LazyAddMod(v0, v2, q); xp[2] = LazySubMod(v0, v2, q); xp[1] = LazyAddMod(v1, v3, q); xp[3] = LazySubMod(v1, v3, q); xp += 4; } while (--blocks != 0); } static void new_ifft_base_flipped(umint_t* xp, long lgN, const new_mod_t& mod) { if (lgN == 0) return; mint_t q = mod.q; if (lgN == 1) { umint_t x0 = LazyReduce2(xp[0], q); umint_t x1 = LazyReduce2(xp[1], q); xp[0] = LazyAddMod(x0, x1, q); xp[1] = LazySubMod(x0, x1, q); return; } const mint_t** wtab = mod.wtab; const mulmod_precon_t** wqinvtab = mod.wqinvtab; long blocks = 1L << (lgN - 2); new_ifft_first_two_layers_flipped(xp, blocks, wtab[2], wqinvtab[2], q); blocks >>= 1; long size = 8; for (long j = 3; j <= lgN; j++, blocks >>= 1, size <<= 1) new_ifft_layer_flipped(xp, blocks, size, wtab[j], wqinvtab[j], q); } static void new_ifft_short1_flipped(umint_t* xp, long lgN, const new_mod_t& mod) { long N = 1L << lgN; if (lgN <= NTL_NEW_FFT_THRESH) { new_ifft_base_flipped(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN]; new_ifft_short1_flipped(xp0, lgN - 1, mod); new_ifft_short1_flipped(xp1, lgN - 1, mod); // (X, Y) -> (X + Y*w, X - Y*w) inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly(xp0[1], xp1[1], wtab[1], q, wqinvtab[1]); inv_butterfly(xp0[2], xp1[2], wtab[2], q, wqinvtab[2]); inv_butterfly(xp0[3], xp1[3], wtab[3], q, wqinvtab[3]); for (long j = 4; j < half; j+=4) { inv_butterfly(xp0[j+0], xp1[j+0], wtab[j+0], q, wqinvtab[j+0]); inv_butterfly(xp0[j+1], xp1[j+1], wtab[j+1], q, wqinvtab[j+1]); inv_butterfly(xp0[j+2], xp1[j+2], wtab[j+2], q, wqinvtab[j+2]); inv_butterfly(xp0[j+3], xp1[j+3], wtab[j+3], q, wqinvtab[j+3]); } } //========= static void new_ifft_short2(umint_t* xp, long yn, long lgN, const new_mod_t& mod) // Implements truncated inverse FFT interface, but with xn==N. // All computations are done in place. { long N = 1L << lgN; if (yn == N && lgN <= NTL_NEW_FFT_THRESH) { // no truncation new_ifft_base(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; mint_t q = mod.q; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j++) xp[j] = LazyDoubleMod4(xp[j], q); // (X, Y) -> X + Y for (long j = yn; j < half; j++) xp[j] = LazyAddMod4(xp[j], xp[j + half], q); new_ifft_short2(xp, yn, lgN - 1, mod); // (X, Y) -> X - Y for (long j = 0; j < yn; j++) xp[j] = LazySubMod4(xp[j], xp[j + half], q); } else { umint_t* NTL_RESTRICT xp0 = xp; umint_t* NTL_RESTRICT xp1 = xp + half; const mint_t* NTL_RESTRICT wtab = mod.wtab[lgN]; const mulmod_precon_t* NTL_RESTRICT wqinvtab = mod.wqinvtab[lgN]; new_ifft_short1(xp0, half, lgN - 1, mod); yn -= half; // (X, Y) -> (2X - Y, w*(X - Y)) for (long j = yn; j < half; j++) { umint_t x0 = xp0[j]; umint_t x1 = xp1[j]; umint_t u = LazySubMod4(x0, x1, q); xp0[j] = LazyAddMod4(x0, u, q); xp1[j] = LazyMulModPrecon(u, wtab[j], q, wqinvtab[j]); } new_ifft_short2(xp1, yn, lgN - 1, mod); // (X, Y) -> (X + Y/w, X - Y/w) { const mint_t* NTL_RESTRICT wtab1 = wtab + half; const mulmod_precon_t* NTL_RESTRICT wqinvtab1 = wqinvtab + half; // DIRT: assumes yn is a multiple of 4 inv_butterfly0(xp0[0], xp1[0], q); inv_butterfly_neg(xp0[1], xp1[1], wtab1[-1], q, wqinvtab1[-1]); inv_butterfly_neg(xp0[2], xp1[2], wtab1[-2], q, wqinvtab1[-2]); inv_butterfly_neg(xp0[3], xp1[3], wtab1[-3], q, wqinvtab1[-3]); for (long j = 4; j < yn; j+=4) { inv_butterfly_neg(xp0[j+0], xp1[j+0], wtab1[-(j+0)], q, wqinvtab1[-(j+0)]); inv_butterfly_neg(xp0[j+1], xp1[j+1], wtab1[-(j+1)], q, wqinvtab1[-(j+1)]); inv_butterfly_neg(xp0[j+2], xp1[j+2], wtab1[-(j+2)], q, wqinvtab1[-(j+2)]); inv_butterfly_neg(xp0[j+3], xp1[j+3], wtab1[-(j+3)], q, wqinvtab1[-(j+3)]); } } } } //============================================= // HIGH LEVEL ROUTINES //=========== FFT without tables =========== NTL_TLS_GLOBAL_DECL(Vec, AA_store) NTL_TLS_GLOBAL_DECL(Vec, mul_vec) void new_fft_notab(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn, long xn) // Performs a high-level FFT. Inputs and outputs are in the range [0,q). // xn and yn are as described above in the truncated FFT interface. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // This version does not use precomputed tables. { mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = A0; A[1] = A1; return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; NTL_TLS_GLOBAL_ACCESS(mul_vec); ComputeMultipliers(mul_vec, k-1, q, qinv, root); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wtab[s] = mul_vec[s].wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wqinvtab[s] = mul_vec[s].wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t w = info.RootTable[0][k]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, info.qinv); #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < xn; i++) AA[i] = a[i]; new_fft_short_notab(AA, yn, xn, k, mod, w, wqinv); for (long i = 0; i < yn; i++) { A[i] = LazyReduce1(AA[i], q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < xn; i++) AA[i] = a[i]; new_fft_short_notab(AA, yn, xn, k, mod, w, wqinv); for (long i = 0; i < yn; i++) { AA[i] = LazyReduce1(AA[i], q); } #endif } void new_fft_flipped_notab(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) // Performs a high-level FFT. Inputs and outputs are in the range [0,q). // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // This version is "flipped" -- it uses inverted roots, // multiplies by 2^{-k}, and performs no truncations. // This version does not use precomputed tables. { mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t two_inv = info.TwoInvTable[1]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[1]; mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = LazyReduce1(LazyMulModPrecon(A0, two_inv, q, two_inv_aux), q); A[1] = LazyReduce1(LazyMulModPrecon(A1, two_inv, q, two_inv_aux), q); return; } } // assume k > 1 const mint_t *root = info.RootTable[1].elts(); mulmod_t qinv = info.qinv; NTL_TLS_GLOBAL_ACCESS(mul_vec); ComputeMultipliers(mul_vec, k-1, q, qinv, root); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wtab[s] = mul_vec[s].wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wqinvtab[s] = mul_vec[s].wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t w = info.RootTable[1][k]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, info.qinv); mint_t two_inv = info.TwoInvTable[k]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[k]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < n; i++) AA[i] = a[i]; new_fft_short_notab(AA, n, n, k, mod, w, wqinv); for (long i = 0; i < n; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < n; i++) AA[i] = a[i]; new_fft_short_notab(AA, n, n, k, mod, w, wqinv); for (long i = 0; i < n; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); AA[i] = LazyReduce1(tmp, q); } #endif } //=========== Inverse FFT without tables =========== void new_ifft_notab(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn) // Performs a high-level IFFT. Inputs and outputs are in the range [0,q). // yn==xn are as described above in the truncated FFT interface. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // Multiplies by 2^{-k}. // This version does not use precomputed tables. { mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t two_inv = info.TwoInvTable[1]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[1]; mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = LazyReduce1(LazyMulModPrecon(A0, two_inv, q, two_inv_aux), q); A[1] = LazyReduce1(LazyMulModPrecon(A1, two_inv, q, two_inv_aux), q); return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; NTL_TLS_GLOBAL_ACCESS(mul_vec); ComputeMultipliers(mul_vec, k-1, q, qinv, root); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wtab[s] = mul_vec[s].wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wqinvtab[s] = mul_vec[s].wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t w = info.RootTable[0][k]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, info.qinv); mint_t iw = info.RootTable[1][k]; mulmod_precon_t iwqinv = LazyPrepMulModPrecon(iw, q, info.qinv); mint_t two_inv = info.TwoInvTable[k]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[k]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < yn; i++) AA[i] = a[i]; new_ifft_short1_notab(AA, yn, k, mod, w, wqinv, iw, iwqinv); for (long i = 0; i < yn; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < yn; i++) AA[i] = a[i]; new_ifft_short1_notab(AA, yn, k, mod, w, wqinv, iw, iwqinv); for (long i = 0; i < yn; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); AA[i] = LazyReduce1(tmp, q); } #endif } void new_ifft_flipped_notab(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) // Performs a high-level IFFT. Inputs and outputs are in the range [0,q). // Flipped means inverse roots are used an no truncation and // no multiplication by 2^{-k}. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // This version does not use precomputed tables. { mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = A0; A[1] = A1; return; } } // assume k > 1 const mint_t *root = info.RootTable[1].elts(); mulmod_t qinv = info.qinv; NTL_TLS_GLOBAL_ACCESS(mul_vec); ComputeMultipliers(mul_vec, k-1, q, qinv, root); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wtab[s] = mul_vec[s].wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k-1; s++) wqinvtab[s] = mul_vec[s].wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t w = info.RootTable[1][k]; mulmod_precon_t wqinv = LazyPrepMulModPrecon(w, q, info.qinv); mint_t iw = info.RootTable[0][k]; mulmod_precon_t iwqinv = LazyPrepMulModPrecon(iw, q, info.qinv); #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < n; i++) AA[i] = a[i]; new_ifft_short1_notab(AA, n, k, mod, w, wqinv, iw, iwqinv); for (long i = 0; i < n; i++) { umint_t tmp = LazyReduce2(AA[i], q); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < n; i++) AA[i] = a[i]; new_ifft_short1_notab(AA, n, k, mod, w, wqinv, iw, iwqinv); for (long i = 0; i < n; i++) { umint_t tmp = LazyReduce2(AA[i], q); AA[i] = LazyReduce1(tmp, q); } #endif } #ifndef NTL_ENABLE_AVX_FFT //================ FFT with tables ============== void new_fft(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn, long xn) // Performs a high-level FFT. Inputs and outputs are in the range [0,q). // xn and yn are as described above in the truncated FFT interface. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. { if (!info.bigtab || k > info.bigtab->bound) { new_fft_notab(A, a, k, info, yn, xn); return; } mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = A0; A[1] = A1; return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; const FFTMultipliers& tab = info.bigtab->MulTab; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < xn; i++) AA[i] = a[i]; new_fft_short(AA, yn, xn, k, mod); for (long i = 0; i < yn; i++) { A[i] = LazyReduce1(AA[i], q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < xn; i++) AA[i] = a[i]; new_fft_short(AA, yn, xn, k, mod); for (long i = 0; i < yn; i++) { AA[i] = LazyReduce1(AA[i], q); } #endif } void new_fft_flipped(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) // Performs a high-level FFT. Inputs and outputs are in the range [0,q). // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // This version is "flipped" -- it uses inverted roots, // multiplies by 2^{-k}, and performs no truncations. { if (!info.bigtab || k > info.bigtab->bound) { new_fft_flipped_notab(A, a, k, info); return; } mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t two_inv = info.TwoInvTable[1]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[1]; mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = LazyReduce1(LazyMulModPrecon(A0, two_inv, q, two_inv_aux), q); A[1] = LazyReduce1(LazyMulModPrecon(A1, two_inv, q, two_inv_aux), q); return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; const FFTMultipliers& tab = info.bigtab->MulTab; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t two_inv = info.TwoInvTable[k]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[k]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < n; i++) AA[i] = a[i]; new_fft_short_flipped(AA, k, mod); for (long i = 0; i < n; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < n; i++) AA[i] = a[i]; new_fft_short_flipped(AA, k, mod); for (long i = 0; i < n; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); AA[i] = LazyReduce1(tmp, q); } #endif } //======= Inverse FFT with tables ============== void new_ifft(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn) // Performs a high-level IFFT. Inputs and outputs are in the range [0,q). // yn==xn are as described above in the truncated FFT interface. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. // Multiples by 2^{-k}. { if (!info.bigtab || k > info.bigtab->bound) { new_ifft_notab(A, a, k, info, yn); return; } mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t two_inv = info.TwoInvTable[1]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[1]; mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = LazyReduce1(LazyMulModPrecon(A0, two_inv, q, two_inv_aux), q); A[1] = LazyReduce1(LazyMulModPrecon(A1, two_inv, q, two_inv_aux), q); return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; const FFTMultipliers& tab = info.bigtab->MulTab; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mint_t two_inv = info.TwoInvTable[k]; mulmod_precon_t two_inv_aux = info.TwoInvPreconTable[k]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < yn; i++) AA[i] = a[i]; new_ifft_short1(AA, yn, k, mod); for (long i = 0; i < yn; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < yn; i++) AA[i] = a[i]; new_ifft_short1(AA, yn, k, mod); for (long i = 0; i < yn; i++) { umint_t tmp = LazyMulModPrecon(AA[i], two_inv, q, two_inv_aux); AA[i] = LazyReduce1(tmp, q); } #endif } void new_ifft_flipped(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) // Performs a high-level IFFT. Inputs and outputs are in the range [0,q). // Flipped means inverse roots are used an no truncation and // no multiplication by 2^{-k}. // Both A and a should point to arrays of size 2^k, // and should either be the same or not overlap at all. { if (!info.bigtab || k > info.bigtab->bound) { new_ifft_flipped_notab(A, a, k, info); return; } mint_t q = info.q; if (k <= 1) { if (k == 0) { A[0] = a[0]; return; } if (k == 1) { mint_t A0 = AddMod(a[0], a[1], q); mint_t A1 = SubMod(a[0], a[1], q); A[0] = A0; A[1] = A1; return; } } // assume k > 1 const mint_t *root = info.RootTable[0].elts(); mulmod_t qinv = info.qinv; const FFTMultipliers& tab = info.bigtab->MulTab; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); long n = 1L << k; const mint_t *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const mulmod_precon_t *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); new_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; #ifdef NTL_FFT_USEBUF NTL_TLS_GLOBAL_ACCESS(AA_store); AA_store.SetLength(1L << k); umint_t *AA = AA_store.elts(); for (long i = 0; i < n; i++) AA[i] = a[i]; new_ifft_short1_flipped(AA, k, mod); for (long i = 0; i < n; i++) { umint_t tmp = LazyReduce2(AA[i], q); A[i] = LazyReduce1(tmp, q); } #else umint_t *AA = (umint_t *) A; if (a != A) for (long i = 0; i < n; i++) AA[i] = a[i]; new_ifft_short1_flipped(AA, k, mod); for (long i = 0; i < n; i++) { umint_t tmp = LazyReduce2(AA[i], q); AA[i] = LazyReduce1(tmp, q); } #endif } #endif //=============================================== void InitFFTPrimeInfo(FFTPrimeInfo& info, long q, long w, long bigtab_index) { mulmod_t qinv = PrepMulMod(q); long mr = CalcMaxRoot(q); info.q = q; info.qinv = qinv; info.qrecip = 1/double(q); info.zz_p_context = 0; info.RootTable[0].SetLength(mr+1); info.RootTable[1].SetLength(mr+1); info.TwoInvTable.SetLength(mr+1); info.TwoInvPreconTable.SetLength(mr+1); long *rt = &info.RootTable[0][0]; long *rit = &info.RootTable[1][0]; long *tit = &info.TwoInvTable[0]; mulmod_precon_t *tipt = &info.TwoInvPreconTable[0]; long j; long t; rt[mr] = w; for (j = mr-1; j >= 0; j--) rt[j] = MulMod(rt[j+1], rt[j+1], q); rit[mr] = InvMod(w, q); for (j = mr-1; j >= 0; j--) rit[j] = MulMod(rit[j+1], rit[j+1], q); t = InvMod(2, q); tit[0] = 1; for (j = 1; j <= mr; j++) tit[j] = MulMod(tit[j-1], t, q); for (j = 0; j <= mr; j++) tipt[j] = LazyPrepMulModPrecon(tit[j], q, qinv); #ifndef NTL_ENABLE_AVX_FFT if (bigtab_index != -1) { long bound = NTL_FFT_BIGTAB_MAXROOT-bigtab_index/NTL_FFT_BIGTAB_LIMIT; if (bound > NTL_FFT_BIGTAB_MINROOT) { info.bigtab.make(); info.bigtab->bound = bound; } } #else // with the AVX implementation, we unconditionally use tables info.bigtab.make(); #endif } //=================================================================== #ifdef NTL_ENABLE_AVX_FFT static void pd_LazyPrepMulModPrecon(double *bninv, const double *b, double n, long len) { CSRPush push; pd_LazyPrepMulModPrecon_impl(bninv, b, n, len); } static void LazyPrecompFFTMultipliers(long k, mint_t q, mulmod_t qinv, const mint_t *root, const pd_FFTMultipliers& tab) { if (k < 1) LogicError("LazyPrecompFFTMultipliers: bad input"); do { // NOTE: thread safe lazy init pd_FFTMultipliers::Builder bld(tab, k+1); long amt = bld.amt(); if (!amt) break; long first = k+1-amt; // initialize entries first..k for (long s = first; s <= k; s++) { UniquePtr item; if (s == 0) { bld.move(item); // position 0 not used continue; } long m = 1L << s; long m_half = 1L << (s-1); item.make(); item->wtab_precomp.SetLength(m_half); item->wqinvtab_precomp.SetLength(m_half); double *wtab = item->wtab_precomp.elts(); double *wqinvtab = item->wqinvtab_precomp.elts(); mint_t w = root[s]; mulmod_precon_t wqinv = PrepMulModPrecon(w, q, qinv); mint_t wi = 1; wtab[0] = wi; for (long i = 1; i < m_half; i++) { wi = MulModPrecon(wi, w, q, wqinv); wtab[i] = wi; } pd_LazyPrepMulModPrecon(wqinvtab, wtab, q, m_half); bld.move(item); } } while (0); } NTL_TLS_GLOBAL_DECL(AlignedArray, pd_AA_store) static NTL_CHEAP_THREAD_LOCAL long pd_AA_store_len = 0; #define PD_MIN_K (NTL_LG2_PDSZ+3) // k must be at least PD_MIN_K void new_fft(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn, long xn) { if (k < PD_MIN_K) { new_fft_notab(A, a, k, info, yn, xn); return; } long dir = 0; mint_t q = info.q; const mint_t *root = info.RootTable[dir].elts(); mulmod_t qinv = info.qinv; const pd_FFTMultipliers& tab = info.bigtab->pd_MulTab[dir]; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); const double *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const double *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); pd_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; long n = 1L << k; NTL_TLS_GLOBAL_ACCESS(pd_AA_store); if (pd_AA_store_len < n) pd_AA_store.SetLength(n); double *AA = pd_AA_store.elts(); CSRPush push; pd_fft_trunc_impl(A, a, AA, k, mod, yn, xn); } void new_fft_flipped(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) { if (k < PD_MIN_K) { new_fft_flipped_notab(A, a, k, info); return; } long dir = 1; mint_t q = info.q; const mint_t *root = info.RootTable[dir].elts(); mulmod_t qinv = info.qinv; const pd_FFTMultipliers& tab = info.bigtab->pd_MulTab[dir]; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); const double *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const double *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); pd_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; long n = 1L << k; NTL_TLS_GLOBAL_ACCESS(pd_AA_store); if (pd_AA_store_len < n) pd_AA_store.SetLength(n); double *AA = pd_AA_store.elts(); CSRPush push; pd_fft_trunc_impl(A, a, AA, k, mod, n, n, info.TwoInvTable[k]); } void new_ifft(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info, long yn) { if (k < PD_MIN_K) { new_ifft_notab(A, a, k, info, yn); return; } long dir = 0; mint_t q = info.q; const mint_t *root = info.RootTable[1-dir].elts(); const mint_t *root1 = info.RootTable[dir].elts(); mulmod_t qinv = info.qinv; const pd_FFTMultipliers& tab = info.bigtab->pd_MulTab[1-dir]; const pd_FFTMultipliers& tab1 = info.bigtab->pd_MulTab[dir]; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); if (k >= tab1.length()) LazyPrecompFFTMultipliers(k, q, qinv, root1, tab1); const double *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const double *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); const double *wtab1[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab1[s] = tab1[s]->wtab_precomp.elts(); const double *wqinvtab1[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab1[s] = tab1[s]->wqinvtab_precomp.elts(); pd_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mod.wtab1 = &wtab1[0]; mod.wqinvtab1 = &wqinvtab1[0]; long n = 1L << k; NTL_TLS_GLOBAL_ACCESS(pd_AA_store); if (pd_AA_store_len < n) pd_AA_store.SetLength(n); double *AA = pd_AA_store.elts(); CSRPush push; pd_ifft_trunc_impl(A, a, AA, k, mod, yn, info.TwoInvTable[k]); } void new_ifft_flipped(mint_t* A, const mint_t* a, long k, const FFTPrimeInfo& info) { if (k < PD_MIN_K) { new_ifft_flipped_notab(A, a, k, info); return; } long dir = 1; mint_t q = info.q; const mint_t *root = info.RootTable[1-dir].elts(); const mint_t *root1 = info.RootTable[dir].elts(); mulmod_t qinv = info.qinv; const pd_FFTMultipliers& tab = info.bigtab->pd_MulTab[1-dir]; const pd_FFTMultipliers& tab1 = info.bigtab->pd_MulTab[dir]; if (k >= tab.length()) LazyPrecompFFTMultipliers(k, q, qinv, root, tab); if (k >= tab1.length()) LazyPrecompFFTMultipliers(k, q, qinv, root1, tab1); const double *wtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab[s] = tab[s]->wtab_precomp.elts(); const double *wqinvtab[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab[s] = tab[s]->wqinvtab_precomp.elts(); const double *wtab1[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wtab1[s] = tab1[s]->wtab_precomp.elts(); const double *wqinvtab1[NTL_FFTMaxRoot+1]; for (long s = 1; s <= k; s++) wqinvtab1[s] = tab1[s]->wqinvtab_precomp.elts(); pd_mod_t mod; mod.q = q; mod.wtab = &wtab[0]; mod.wqinvtab = &wqinvtab[0]; mod.wtab1 = &wtab1[0]; mod.wqinvtab1 = &wqinvtab1[0]; long n = 1L << k; NTL_TLS_GLOBAL_ACCESS(pd_AA_store); if (pd_AA_store_len < n) pd_AA_store.SetLength(n); double *AA = pd_AA_store.elts(); CSRPush push; pd_ifft_trunc_impl(A, a, AA, k, mod, n); } #endif NTL_END_IMPL ntl-11.5.1/src/FacVec.cpp0000644417616742025610000000263614064716022016606 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL static void swap(IntFactor& x, IntFactor& y) { IntFactor t; t = x; x = y; y = t; } static void FindMin(FacVec& v, long lo, long hi) { long minv = 0; long minp = -1; long i; for (i = lo; i <= hi; i++) { if (minv == 0 || v[i].val < minv) { minv = v[i].val; minp = i; } } swap(v[lo], v[minp]); } void FactorInt(FacVec& fvec, long n) { if (n <= 1) LogicError("internal error: FactorInt(FacVec,long n) with n<=1"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("internal error: FactorInt(FacVec,long n) with n too large"); long NumFactors; long q; fvec.SetLength(2*NextPowerOfTwo(n)); NumFactors = 0; q = 2; while (n != 1) { if (n%q == 0) { fvec[NumFactors].q = q; n = n/q; fvec[NumFactors].a = 1; fvec[NumFactors].val = q; while (n%q == 0) { n = n/q; (fvec[NumFactors].a)++; fvec[NumFactors].val *= q; } fvec[NumFactors].link = -1; NumFactors++; } q++; } fvec.SetLength(2*NumFactors-1); long lo = 0; long hi = NumFactors - 1; while (lo < hi) { FindMin(fvec, lo, hi); FindMin(fvec, lo+1, hi); hi++; fvec[hi].link = lo; fvec[hi].val = fvec[lo].val * fvec[lo+1].val; lo += 2; } } NTL_END_IMPL ntl-11.5.1/src/GF2.cpp0000644417616742025610000000072714064716022016034 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL GF2 power(GF2 a, long e) { if (e == 0) { return to_GF2(1); } if (e < 0 && IsZero(a)) ArithmeticError("GF2: division by zero"); return a; } ostream& operator<<(ostream& s, GF2 a) { if (a == 0) s << "0"; else s << "1"; return s; } istream& operator>>(istream& s, ref_GF2 x) { NTL_ZZRegister(a); NTL_INPUT_CHECK_RET(s, s >> a); conv(x, a); return s; } NTL_END_IMPL ntl-11.5.1/src/GF2E.cpp0000644417616742025610000001470114064716022016136 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL NTL_TLS_GLOBAL_DECL(SmartPtr, GF2EInfo_stg) NTL_CHEAP_THREAD_LOCAL GF2EInfoT *GF2EInfo = 0; GF2EInfoT::GF2EInfoT(const GF2X& NewP) { build(p, NewP); _card_exp = p.n; long sz = p.size; // The following crossovers were set using the programs // GF2EXKarCross.cpp, GF2EXModCross.cpp, GF2EXModCross.cpp, // and GF2EXGCDCross.cpp. // To use these programs, one has to remove the #if 0 guards // in GF2EX.cpp on mul_disable_plain, BuildPlain, and DivRemPlain. // There are three different configurations that are treated separately: // * with gf2x lib and with pclmul instruction available // * without gf2x lib but with pclmul // * without gf2X lib and without pclmul // It is possible that one could be using gf2x lib on a platform without // pclmul, in which case the crossovers used here are not optimal. It is also // possible that one could be using gf2x lib with pclmul, but compile NTL with // NATIVE=off, so that NTL assumes there is no pclmul. Again, this will lead // to crossovers that are not optimal. // The crossovers were calculated based on a Skylake Xeon processor: // Intel(R) Xeon(R) Gold 6132 CPU @ 2.60GHz. #if (defined(NTL_GF2X_LIB) && defined(NTL_HAVE_PCLMUL)) //========== KarCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) KarCross = 3; else KarCross = 4; } else if (sz <= 6) KarCross = 8; else if (sz <= 9) KarCross = 4; else KarCross = 2; //========== ModCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) ModCross = 15; else ModCross = 20; } else if (sz <= 9) ModCross = 60; else if (sz <= 18) ModCross = 25; else ModCross = 15; //========== DivCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) DivCross = 50; else DivCross = 75; } else if (sz <= 2) DivCross = 100; else if (sz <= 3) DivCross = 150; else if (sz <= 4) DivCross = 200; else if (sz <= 6) DivCross = 250; else if (sz <= 9) DivCross = 225; else if (sz <= 15) DivCross = 125; else if (sz < 125) DivCross = 100; else DivCross = 75; //========== GCDCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) GCDCross = 225; else GCDCross = 225; } else if (sz <= 2) GCDCross = 450; else if (sz <= 4) GCDCross = 600; else if (sz < 12) GCDCross = 1150; else GCDCross = 600; #elif (defined(NTL_HAVE_PCLMUL)) //========== KarCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) KarCross = 5; else KarCross = 8; } else if (sz <= 5) KarCross = 8; else if (sz <= 9) KarCross = 4; else KarCross = 2; //========== ModCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) ModCross = 30; else ModCross = 45; } else if (sz <= 2) ModCross = 110; else if (sz <= 3) ModCross = 105; else if (sz <= 4) ModCross = 65; else if (sz <= 5) ModCross = 60; else if (sz <= 6) ModCross = 55; else if (sz <= 8) ModCross = 50; else if (sz <= 12) ModCross = 30; else if (sz <= 18) ModCross = 25; else ModCross = 15; //========== DivCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) DivCross = 75; else DivCross = 125; } else if (sz <= 2) DivCross = 450; else if (sz <= 3) DivCross = 425; else if (sz <= 4) DivCross = 375; else if (sz <= 6) DivCross = 250; else if (sz <= 8) DivCross = 225; else if (sz <= 16) DivCross = 125; else if (sz <= 45) DivCross = 100; else DivCross = 75; //========== GCDCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) GCDCross = 225; else GCDCross = 225; } else if (sz < 12) GCDCross = 1150; else GCDCross = 850; #else //========== KarCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) KarCross = 4; else KarCross = 12; } else if (sz <= 3) KarCross = 4; else KarCross = 2; //========== ModCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) ModCross = 45; else ModCross = 65; } else if (sz <= 2) ModCross = 25; else ModCross = 15; //========== DivCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) DivCross = 175; else DivCross = 250; } else if (sz <= 4) DivCross = 100; else DivCross = 75; //========== GCDCross ========== if (sz <= 1) { if (deg(p) <= NTL_BITS_PER_LONG/2) GCDCross = 225; else GCDCross = 850; } else if (sz < 8) GCDCross = 850; else if (sz < 12) GCDCross = 600; else GCDCross = 450; #endif } const ZZ& GF2E::cardinality() { if (!GF2EInfo) LogicError("GF2E::cardinality: undefined modulus"); do { // NOTE: thread safe lazy init Lazy::Builder builder(GF2EInfo->_card); if (!builder()) break; UniquePtr p; p.make(); power(*p, 2, GF2EInfo->_card_exp); builder.move(p); } while (0); return *GF2EInfo->_card; } void GF2E::init(const GF2X& p) { GF2EContext c(p); c.restore(); } void GF2EContext::save() { NTL_TLS_GLOBAL_ACCESS(GF2EInfo_stg); ptr = GF2EInfo_stg; } void GF2EContext::restore() const { NTL_TLS_GLOBAL_ACCESS(GF2EInfo_stg); GF2EInfo_stg = ptr; GF2EInfo = GF2EInfo_stg.get(); } GF2EBak::~GF2EBak() { if (MustRestore) c.restore(); } void GF2EBak::save() { c.save(); MustRestore = true; } void GF2EBak::restore() { c.restore(); MustRestore = false; } const GF2E& GF2E::zero() { static const GF2E z(INIT_NO_ALLOC); // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, GF2E& x) { GF2X y; NTL_INPUT_CHECK_RET(s, s >> y); conv(x, y); return s; } void div(GF2E& x, const GF2E& a, const GF2E& b) { GF2E t; inv(t, b); mul(x, a, t); } void div(GF2E& x, GF2 a, const GF2E& b) { inv(x, b); mul(x, x, a); } void div(GF2E& x, long a, const GF2E& b) { inv(x, b); mul(x, x, a); } void inv(GF2E& x, const GF2E& a) { InvMod(x._GF2E__rep, a._GF2E__rep, GF2E::modulus()); } NTL_END_IMPL ntl-11.5.1/src/GF2EX.cpp0000644417616742025610000020562214064716022016272 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL const GF2EX& GF2EX::zero() { static const GF2EX z; // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, GF2EX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const GF2EX& a) { return s << a.rep; } void GF2EX::normalize() { long n; const GF2E* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const GF2EX& a) { return a.rep.length() == 0; } long IsOne(const GF2EX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(GF2E& x, const GF2EX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(GF2EX& x, long i, const GF2E& a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) LogicError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { GF2E aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(GF2EX& x, long i, GF2 a) { if (i < 0) LogicError("SetCoeff: negative index"); if (a == 1) SetCoeff(x, i); else SetCoeff(x, i, GF2E::zero()); } void SetCoeff(GF2EX& x, long i, long a) { if (i < 0) LogicError("SetCoeff: negative index"); if ((a & 1) == 1) SetCoeff(x, i); else SetCoeff(x, i, GF2E::zero()); } void SetCoeff(GF2EX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(GF2EX& x) { clear(x); SetCoeff(x, 1); } long IsX(const GF2EX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const GF2E& coeff(const GF2EX& a, long i) { if (i < 0 || i > deg(a)) return GF2E::zero(); else return a.rep[i]; } const GF2E& LeadCoeff(const GF2EX& a) { if (IsZero(a)) return GF2E::zero(); else return a.rep[deg(a)]; } const GF2E& ConstTerm(const GF2EX& a) { if (IsZero(a)) return GF2E::zero(); else return a.rep[0]; } void conv(GF2EX& x, const GF2E& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(GF2EX& x, long a) { if (a & 1) set(x); else clear(x); } void conv(GF2EX& x, GF2 a) { if (a == 1) set(x); else clear(x); } void conv(GF2EX& x, const ZZ& a) { if (IsOdd(a)) set(x); else clear(x); } void conv(GF2EX& x, const GF2X& aa) { GF2X a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(GF2EX& x, const vec_GF2E& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(GF2EX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(GF2EX& x, const GF2EX& a, const GF2EX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const GF2E *ap, *bp; GF2E* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(GF2EX& x, const GF2EX& a, const GF2E& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x GF2E *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const GF2E *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(GF2EX& x, const GF2EX& a, GF2 b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void add(GF2EX& x, const GF2EX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void PlainMul(GF2EX& x, const GF2EX& a, const GF2EX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } if (&a == &b) { sqr(x, a); return; } long d = da+db; const GF2E *ap, *bp; GF2E *xp; GF2EX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; GF2X t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void sqr(GF2EX& x, const GF2EX& a) { long da = deg(a); if (da < 0) { clear(x); return; } x.rep.SetLength(2*da+1); long i; for (i = da; i > 0; i--) { sqr(x.rep[2*i], a.rep[i]); clear(x.rep[2*i-1]); } sqr(x.rep[0], a.rep[0]); x.normalize(); } static void PlainMul1(GF2X *xp, const GF2X *ap, long sa, const GF2X& b) { long i; for (i = 0; i < sa; i++) mul(xp[i], ap[i], b); } static inline void q_add(GF2X& x, const GF2X& a, const GF2X& b) // This is a quick-and-dirty add routine used by the karatsuba routine. // It assumes that the output already has enough space allocated, // thus avoiding any procedure calls. // WARNING: it also accesses the underlying WordVector representation // directly...that is dirty!. // It shaves a few percent off the running time. { _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); long sa = ap[-1]; long sb = bp[-1]; long i; if (sa == sb) { for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; i = sa-1; while (i >= 0 && !xp[i]) i--; xp[-1] = i+1; } else if (sa < sb) { for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sb; i++) xp[i] = bp[i]; xp[-1] = sb; } else { // sa > sb for (i = 0; i < sb; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sa; i++) xp[i] = ap[i]; xp[-1] = sa; } } static inline void q_copy(GF2X& x, const GF2X& a) // see comments for q_add above { _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long sa = ap[-1]; long i; for (i = 0; i < sa; i++) xp[i] = ap[i]; xp[-1] = sa; } static void KarFold(GF2X *T, const GF2X *b, long sb, long hsa) { long m = sb - hsa; long i; for (i = 0; i < m; i++) q_add(T[i], b[i], b[hsa+i]); for (i = m; i < hsa; i++) q_copy(T[i], b[i]); } static void KarAdd(GF2X *T, const GF2X *b, long sb) { long i; for (i = 0; i < sb; i++) q_add(T[i], T[i], b[i]); } static void KarFix(GF2X *c, const GF2X *b, long sb, long hsa) { long i; for (i = 0; i < hsa; i++) q_copy(c[i], b[i]); for (i = hsa; i < sb; i++) q_add(c[i], c[i], b[i]); } static void KarMul(GF2X *c, const GF2X *a, long sa, const GF2X *b, long sb, GF2X *stk, long sp) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const GF2X *t = a; a = b; b = t; } } if (sb == 1) { if (sa == 1) mul(*c, *a, *b); else PlainMul1(c, a, sa, *b); return; } if (sa == 2) { /* (1 < sb <= sa == 2) implies sb == 2 */ q_add(c[0], a[0], a[1]); q_add(c[2], b[0], b[1]); mul(c[1], c[0], c[2]); mul(c[0], a[0], b[0]); mul(c[2], a[1], b[1]); q_add(c[1], c[1], c[0]); q_add(c[1], c[1], c[2]); return; } if (sa == 3 && sb == 3) { q_add(c[0], a[0], a[2]); /* a_0 + a_2 */ q_add(c[2], a[1], a[2]); /* a_1 + a_2 */ q_add(c[1], b[0], b[2]); /* b_0 + b_2 */ q_add(c[4], b[1], b[2]); /* b_1 + b_2 */ mul(c[3], c[2], c[4]); /* (a_1 + a_2) x (b_1 + b_2) */ mul(c[2], c[0], c[1]); /* (a_0 + a_2) x (b_0 + b_2) */ q_add(c[0], a[0], a[1]); /* a_0 + a_1 */ q_add(c[4], b[0], b[1]); /* b_0 + b_1 */ mul(c[1], c[0], c[4]); /* (a_0 + a_1) x (b_0 + b_1) */ mul(c[0], a[1], b[1]); /* (a_1) x (b_1) */ q_add(c[1], c[1], c[0]); q_add(c[3], c[3], c[0]); q_add(c[2], c[2], c[0]); mul(c[0], a[0], b[0]); /* (a_0) x (b_0) */ q_add(c[1], c[1], c[0]); q_add(c[2], c[2], c[0]); mul(c[4], a[2], b[2]); /* (a_2) x (b_2) */ q_add(c[3], c[3], c[4]); q_add(c[2], c[2], c[4]); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; GF2X *T1, *T2, *T3; sp -= hsa2 - 1; if (sp < 0) TerminalError("internal error: KarMul overflow"); T1 = c; T2 = c + hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk, sp); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk, sp); KarAdd(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk, sp); KarAdd(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ GF2X *T; sp -= hsa + sb - 1; if (sp < 0) TerminalError("internal error: KarMul overflow"); T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk, sp); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk, sp); KarFix(c, T, hsa + sb - 1, hsa); } } void ExtractBits(_ntl_ulong *cp, const _ntl_ulong *ap, long k, long n) // extract k bits from a at position n { long sc = (k + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long i; if (bn == 0) { for (i = 0; i < sc; i++) cp[i] = ap[i+wn]; } else { for (i = 0; i < sc-1; i++) cp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); if (k > sc*NTL_BITS_PER_LONG - bn) cp[sc-1] = (ap[sc+wn-1] >> bn)|(ap[sc+wn] << (NTL_BITS_PER_LONG - bn)); else cp[sc-1] = ap[sc+wn-1] >> bn; } long p = k % NTL_BITS_PER_LONG; if (p != 0) cp[sc-1] &= ((1UL << p) - 1UL); } void KronSubst(GF2X& aa, const GF2EX& a) { long sa = a.rep.length(); long blocksz = 2*GF2E::degree() - 1; long saa = sa*blocksz; long wsaa = (saa + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; aa.xrep.SetLength(wsaa+1); _ntl_ulong *paa = aa.xrep.elts(); long i; for (i = 0; i < wsaa+1; i++) paa[i] = 0; for (i = 0; i < sa; i++) ShiftAdd(paa, rep(a.rep[i]).xrep.elts(), rep(a.rep[i]).xrep.length(), blocksz*i); aa.normalize(); } void KronMul(GF2EX& x, const GF2EX& a, const GF2EX& b) { if (a == 0 || b == 0) { clear(x); return; } GF2X aa, bb, xx; long sx = deg(a) + deg(b) + 1; long blocksz = 2*GF2E::degree() - 1; if (NTL_OVERFLOW(blocksz, sx, 0)) ResourceError("overflow in GF2EX KronMul"); KronSubst(aa, a); KronSubst(bb, b); mul(xx, aa, bb); GF2X c; long wc = (blocksz + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; x.rep.SetLength(sx); long i; for (i = 0; i < sx-1; i++) { c.xrep.SetLength(wc); ExtractBits(c.xrep.elts(), xx.xrep.elts(), blocksz, i*blocksz); c.normalize(); conv(x.rep[i], c); } long last_blocksz = deg(xx) - (sx-1)*blocksz + 1; wc = (last_blocksz + NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; c.xrep.SetLength(wc); ExtractBits(c.xrep.elts(), xx.xrep.elts(), last_blocksz, (sx-1)*blocksz); c.normalize(); conv(x.rep[sx-1], c); x.normalize(); } void mul(GF2EX& c, const GF2EX& a, const GF2EX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long sa = a.rep.length(); long sb = b.rep.length(); if (sa == 1) { mul(c, b, a.rep[0]); return; } if (sb == 1) { mul(c, a, b.rep[0]); return; } if (sa < GF2E::KarCross() || sb < GF2E::KarCross()) { PlainMul(c, a, b); return; } bool use_kron_mul = false; if (GF2E::WordLength() <= 1) use_kron_mul = true; #if (defined(NTL_GF2X_LIB) && defined(NTL_HAVE_PCLMUL)) // With gf2x library and pclmul, KronMul is better in a larger range, but // it is very hard to characterize that range. The following is very // conservative. if (GF2E::WordLength() <= 4 && sa >= 50 && sb >= 50) use_kron_mul = true; // FIXME: figure out a larger range where KronMul is better // (and don't forget to recompute crossovers in GF2E.cpp). #endif if (use_kron_mul) { KronMul(c, a, b); return; } /* karatsuba */ long n, hn, sp; n = max(sa, sb); sp = 0; do { hn = (n+1) >> 1; sp += (hn << 1) - 1; n = hn; } while (n > 1); GF2XVec stk; stk.SetSize(sp + 2*(sa+sb)-1, 2*GF2E::WordLength()); long i; for (i = 0; i < sa; i++) stk[i+sa+sb-1] = rep(a.rep[i]); for (i = 0; i < sb; i++) stk[i+2*sa+sb-1] = rep(b.rep[i]); KarMul(&stk[0], &stk[sa+sb-1], sa, &stk[2*sa+sb-1], sb, &stk[2*(sa+sb)-1], sp); c.rep.SetLength(sa+sb-1); for (i = 0; i < sa+sb-1; i++) conv(c.rep[i], stk[i]); c.normalize(); } #if 0 // used only for computing KarCross using GF2EXKarCross.cpp void mul_disable_plain(GF2EX& c, const GF2EX& a, const GF2EX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long sa = a.rep.length(); long sb = b.rep.length(); if (sa == 1) { mul(c, b, a.rep[0]); return; } if (sb == 1) { mul(c, a, b.rep[0]); return; } if (0) { //if (sa < GF2E::KarCross() || sb < GF2E::KarCross()) { PlainMul(c, a, b); return; } if (GF2E::WordLength() <= 1) { KronMul(c, a, b); return; } /* karatsuba */ long n, hn, sp; n = max(sa, sb); sp = 0; do { hn = (n+1) >> 1; sp += (hn << 1) - 1; n = hn; } while (n > 1); GF2XVec stk; stk.SetSize(sp + 2*(sa+sb)-1, 2*GF2E::WordLength()); long i; for (i = 0; i < sa; i++) stk[i+sa+sb-1] = rep(a.rep[i]); for (i = 0; i < sb; i++) stk[i+2*sa+sb-1] = rep(b.rep[i]); KarMul(&stk[0], &stk[sa+sb-1], sa, &stk[2*sa+sb-1], sb, &stk[2*(sa+sb)-1], sp); c.rep.SetLength(sa+sb-1); for (i = 0; i < sa+sb-1; i++) conv(c.rep[i], stk[i]); c.normalize(); } #endif void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n) { GF2EX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(GF2EX& x, const GF2EX& a, long n) { GF2EX t; sqr(t, a); trunc(x, t, n); } void PlainDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2EX: division by zero"); if (da < db) { r = a; clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1, 2*GF2E::WordLength()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(GF2EX& r, const GF2EX& a, const GF2EX& b, GF2XVec& x) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2EX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b, GF2XVec& x) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2EX: division by zero"); if (da < db) { r = a; clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(GF2EX& q, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2E *qp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2EX: division by zero"); if (da < db) { clear(q); return; } GF2EX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1 - db, 2*GF2E::WordLength()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(GF2EX& r, const GF2EX& a, const GF2EX& b) { long da, db, dq, i, j, LCIsOne; const GF2E *bp; GF2X *xp; GF2E LCInv, t; GF2X s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2EX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } GF2XVec x(da + 1, 2*GF2E::WordLength()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void mul(GF2EX& x, const GF2EX& a, const GF2E& b) { if (IsZero(a) || IsZero(b)) { clear(x); return; } GF2X bb, t; long i, da; const GF2E *ap; GF2E* xp; bb = rep(b); da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) { mul(t, rep(ap[i]), bb); conv(xp[i], t); } x.normalize(); } void mul(GF2EX& x, const GF2EX& a, GF2 b) { if (b == 0) clear(x); else x = a; } void mul(GF2EX& x, const GF2EX& a, long b) { if ((b & 1) == 0) clear(x); else x = a; } void PlainGCD(GF2EX& x, const GF2EX& a, const GF2EX& b) { GF2E t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; GF2EX u(INIT_SIZE, n), v(INIT_SIZE, n); GF2XVec tmp(n, 2*GF2E::WordLength()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } class _NTL_GF2EXMatrix { private: _NTL_GF2EXMatrix(const _NTL_GF2EXMatrix&); // disable GF2EX elts[2][2]; public: _NTL_GF2EXMatrix() { } ~_NTL_GF2EXMatrix() { } void operator=(const _NTL_GF2EXMatrix&); GF2EX& operator() (long i, long j) { return elts[i][j]; } const GF2EX& operator() (long i, long j) const { return elts[i][j]; } }; void _NTL_GF2EXMatrix::operator=(const _NTL_GF2EXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } static void mul(GF2EX& U, GF2EX& V, const _NTL_GF2EXMatrix& M) // (U, V)^T = M*(U, V)^T { GF2EX t1, t2, t3; mul(t1, M(0,0), U); mul(t2, M(0,1), V); add(t3, t1, t2); mul(t1, M(1,0), U); mul(t2, M(1,1), V); add(V, t1, t2); U = t3; } static void mul(_NTL_GF2EXMatrix& A, _NTL_GF2EXMatrix& B, _NTL_GF2EXMatrix& C) // A = B*C, B and C are destroyed { GF2EX t1, t2; mul(t1, B(0,0), C(0,0)); mul(t2, B(0,1), C(1,0)); add(A(0,0), t1, t2); mul(t1, B(1,0), C(0,0)); mul(t2, B(1,1), C(1,0)); add(A(1,0), t1, t2); mul(t1, B(0,0), C(0,1)); mul(t2, B(0,1), C(1,1)); add(A(0,1), t1, t2); mul(t1, B(1,0), C(0,1)); mul(t2, B(1,1), C(1,1)); add(A(1,1), t1, t2); long i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { B(i,j).kill(); C(i,j).kill(); } } } void IterHalfGCD(_NTL_GF2EXMatrix& M_out, GF2EX& U, GF2EX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; GF2EX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } #define NTL_GF2EX_HalfGCD_CROSSOVER (40) void HalfGCD(_NTL_GF2EXMatrix& M_out, const GF2EX& U, const GF2EX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; GF2EX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_GF2EX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2EXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } GF2EX Q; _NTL_GF2EXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); GF2EX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(_NTL_GF2EXMatrix& M_out, GF2EX& U, GF2EX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_GF2EX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; //ZZ_pXMatrix M1; _NTL_GF2EXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } GF2EX Q; _NTL_GF2EXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); GF2EX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(GF2EX& U, GF2EX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2EXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); GF2EX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(GF2EX& d, const GF2EX& u, const GF2EX& v) { GF2EX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) >= GF2E::GCDCross() && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b) { GF2E w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } GF2EX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } _NTL_GF2EXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) LogicError("MulMod: bad args"); GF2EX t; mul(t, a, b); rem(x, t, f); } void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("SqrMod: bad args"); GF2EX t; sqr(t, a); rem(x, t, f); } void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); GF2EX d, xx, t; XGCD(d, xx, t, a, f); if (!IsOne(d)) InvModError("GF2EX InvMod: can't compute multiplicative inverse"); x = xx; } long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvModStatus: bad args"); GF2EX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } static void MulByXModAux(GF2EX& h, const GF2EX& a, const GF2EX& f) { long i, n, m; GF2E* hh; const GF2E *aa, *ff; GF2E t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); z = aa[n-1]; if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(GF2EX& h, const GF2EX& a, const GF2EX& f) { if (&h == &f) { GF2EX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(GF2EX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void CopyReverse(GF2EX& x, const GF2EX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const GF2E* ap = a.rep.elts(); GF2E* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(GF2EX& x, const GF2EX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; GF2E* xp; const GF2E* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void NewtonInvTrunc(GF2EX& c, const GF2EX& a, long e) { GF2E x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); GF2EX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); add(g, g, g2); } c = g; } void InvTrunc(GF2EX& c, const GF2EX& a, long e) { if (e < 0) LogicError("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) ResourceError("overflow in InvTrunc"); NewtonInvTrunc(c, a, e); } const long GF2EX_MOD_PLAIN = 0; const long GF2EX_MOD_MUL = 1; void build(GF2EXModulus& F, const GF2EX& f) { long n = deg(f); if (n <= 0) LogicError("build(GF2EXModulus,GF2EX): deg(f) <= 0"); if (NTL_OVERFLOW(n, GF2E::degree(), 0)) ResourceError("build(GF2EXModulus,GF2EX): overflow"); F.tracevec.make(); F.f = f; F.n = n; if (F.n < GF2E::ModCross()) { F.method = GF2EX_MOD_PLAIN; } else { F.method = GF2EX_MOD_MUL; GF2EX P1; GF2EX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } #if 0 // used only for computing ModCross using GF2EXModCross.cpp void BuildPlain(GF2EXModulus& F, const GF2EX& f, bool plain) { long n = deg(f); if (n <= 0) LogicError("build(GF2EXModulus,GF2EX): deg(f) <= 0"); if (NTL_OVERFLOW(n, GF2E::degree(), 0)) ResourceError("build(GF2EXModulus,GF2EX): overflow"); F.tracevec.make(); F.f = f; F.n = n; if (plain) { F.method = GF2EX_MOD_PLAIN; } else { F.method = GF2EX_MOD_MUL; GF2EX P1; GF2EX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } #endif GF2EXModulus::GF2EXModulus() { n = -1; method = GF2EX_MOD_PLAIN; } GF2EXModulus::GF2EXModulus(const GF2EX& ff) { n = -1; method = GF2EX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); } void UseMulDivRem21(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); q = P2; } void UseMulDiv21(GF2EX& q, const GF2EX& a, const GF2EXModulus& F) { GF2EX P1; GF2EX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); GF2EX qbuf(INIT_SIZE, n-1); GF2EX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } GF2EX buf(INIT_SIZE, 2*n-1); GF2EX qbuf(INIT_SIZE, n-1); GF2EX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(GF2EX& c, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) LogicError("MulMod: bad args"); GF2EX t; mul(t, a, b); rem(c, t, F); } void SqrMod(GF2EX& c, const GF2EX& a, const GF2EXModulus& F) { if (deg(a) >= F.n) LogicError("MulMod: bad args"); GF2EX t; sqr(t, a); rem(c, t, F); } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(GF2EX& h, const GF2EX& g, const ZZ& e, const GF2EXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); GF2EX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 5); vec_GF2EX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { GF2EX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void PowerXMod(GF2EX& hh, const ZZ& e, const GF2EXModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; GF2EX h; h.SetMaxLength(F.n+1); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(h, h, F.f); } } if (e < 0) InvMod(h, h, F); hh = h; } void UseMulRem(GF2EX& r, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; } void UseMulDivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; q = P2; } void UseMulDiv(GF2EX& q, const GF2EX& a, const GF2EX& b) { GF2EX P1; GF2EX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { GF2EXModulus B; build(B, b); DivRem(q, r, a, B); } } #if 0 // used only for computing DivCross using GF2EXDivCross.cpp void DivRemPlain(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b, bool plain) { long sa = a.rep.length(); long sb = b.rep.length(); if (plain) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { GF2EXModulus B; build(B, b); DivRem(q, r, a, B); } } #endif void div(GF2EX& q, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { GF2EXModulus B; build(B, b); div(q, a, B); } } void div(GF2EX& q, const GF2EX& a, const GF2E& b) { GF2E t; inv(t, b); mul(q, a, t); } void div(GF2EX& q, const GF2EX& a, GF2 b) { if (b == 0) ArithmeticError("div: division by zero"); q = a; } void div(GF2EX& q, const GF2EX& a, long b) { if ((b & 1) == 0) ArithmeticError("div: division by zero"); q = a; } void rem(GF2EX& r, const GF2EX& a, const GF2EX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < GF2E::DivCross() || sa-sb < GF2E::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { GF2EXModulus B; build(B, b); rem(r, a, B); } } void diff(GF2EX& x, const GF2EX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { if ((i+1)&1) x.rep[i] = a.rep[i+1]; else clear(x.rep[i]); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void RightShift(GF2EX& x, const GF2EX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(GF2EX& x, const GF2EX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(GF2EX& U, const GF2EX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void IterBuild(GF2E* a, long n) { long i, k; GF2E b, t; if (n <= 0) return; for (k = 1; k <= n-1; k++) { b = a[k]; add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(GF2EX& x, const vec_GF2E& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(GF2E& b, const GF2EX& f, const GF2E& a) // does a Horner evaluation { GF2E acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_GF2E bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b) { long m = a.length(); if (b.length() != m) LogicError("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_GF2E prod; prod = a; GF2E t1, t2; long k, i; vec_GF2E res; res.SetLength(m); for (k = 0; k < m; k++) { const GF2E& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(GF2EX& x, const vec_GF2E& v, long low, long high, const vec_GF2EX& H, long n, GF2XVec& t) { GF2X s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_GF2E& h = H[i-low].rep; long m = h.length(); const GF2X& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& A, const GF2EXModulus& F) { if (deg(g) <= 0) { x = g; return; } GF2EX s, t; GF2XVec scratch(F.n, 2*GF2E::WordLength()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const GF2EX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(GF2EXArgument& A, const GF2EX& h, const GF2EXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) LogicError("build GF2EXArgument: bad args"); if (m > F.n) m = F.n; if (GF2EXArgBound > 0) { double sz = GF2E::storage(); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_GF2E); sz = sz/1024; m = min(m, long(GF2EXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_CHEAP_THREAD_LOCAL long GF2EXArgBound = 0; void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } GF2EXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } GF2EXArgument A; build(A, h, F, m); GF2EX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } GF2EXArgument A; build(A, h, F, m); GF2EX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); GF2EX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(GF2EX& x, const GF2EX& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); GF2EX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); add(x, t1, t2); } void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { GF2EX xx; TransMulMod(xx, to_GF2EX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_GF2E& x, const GF2EX& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { if (k < 0 || deg(a) >= F.n) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2EXTransMultiplier M; build(M, H.H[m], F); GF2EX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_GF2E& x, const GF2EX& a, long k, const GF2EX& h, const GF2EXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); GF2EXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { ProjectPowers(x, to_GF2EX(a), k, H, F); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F) { ProjectPowers(x, to_GF2EX(a), k, h, F); } void BerlekampMassey(GF2EX& h, const vec_GF2E& a, long m) { GF2EX Lambda, Sigma, Temp; long L; GF2E Delta, Delta1, t1; long shamt; GF2X tt1, tt2; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(tt1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(tt2, rep(Lambda.rep[i]), rep(a[r-i-1])); add(tt1, tt1, tt2); } conv(Delta1, tt1); if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftAdd(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftAdd(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m, const GF2EX& R) { vec_GF2E x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); GF2EX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ GF2EX h2, h3; GF2EX R; GF2EXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m) { if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); GF2EX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F) { MinPolyMod(hh, g, F, F.n); } void MakeMonic(GF2EX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; GF2E t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(GF2EX& q, const GF2EX& a, const GF2EX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } GF2EX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const GF2EX& a, const GF2EX& b) { if (IsZero(b)) return IsZero(a); GF2EX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } long operator==(const GF2EX& a, long b) { if (b & 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2EX& a, GF2 b) { if (b == 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2EX& a, const GF2E& b) { if (IsZero(b)) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } void power(GF2EX& x, const GF2EX& a, long e) { if (e < 0) { ArithmeticError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); GF2EX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(GF2EX& x, const GF2EX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { GF2EX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } static void FastTraceVec(vec_GF2E& S, const GF2EXModulus& f) { long n = deg(f); GF2EX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_GF2E& S, const GF2EX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); GF2EX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; GF2X acc, t; GF2E t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_GF2E& S, const GF2EX& f) { if (deg(f) < GF2E::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(vec_GF2E& S, const GF2EXModulus& F) { if (F.method == GF2EX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); InnerProduct(x, a.rep, *F.tracevec.val()); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(GF2E& rres, const GF2EX& a, const GF2EX& b) { GF2E res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; GF2E lc; set(res); long n = max(deg(a),deg(b)) + 1; GF2EX u(INIT_SIZE, n), v(INIT_SIZE, n); GF2XVec tmp(n, 2*GF2E::WordLength()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } rres = res; } } void resultant(GF2E& rres, const GF2EX& a, const GF2EX& b) { PlainResultant(rres, a, b); } void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } GF2E t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { GF2E t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(GF2EX& x, const GF2X& v, long low, long high, const vec_GF2EX& H, long n, vec_GF2E& t) { long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, deg(v)); for (i = low; i <= high; i++) { const vec_GF2E& h = H[i-low].rep; long m = h.length(); if (coeff(v, i) != 0) { for (j = 0; j < m; j++) { add(t[j], t[j], h[j]); } } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } GF2EX s, t; vec_GF2E scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = (((deg(g)+1)+m-1)/m) - 1; const GF2EX& M = A.H[m]; InnerProduct(t, g, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F) // x = g(h) mod f { long m = SqrRoot(deg(g)+1); if (m == 0) { clear(x); return; } GF2EXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_GF2& tt, const vec_GF2E& s, const vec_GF2& proj) { long l = s.length(); tt.SetLength(l); GF2XTransMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), GF2E::modulus()); UpdateMap(tt[i], proj, M, GF2E::modulus()); } } void ProjectedInnerProduct(ref_GF2 x, const vec_GF2E& a, const vec_vec_GF2& b) { long n = min(a.length(), b.length()); GF2 t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_GF2& proj, const GF2X& f) { long n = deg(f); if (n <= 0) LogicError("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_GF2& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F, const vec_GF2& proj) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2EXTransMultiplier M; build(M, H.H[m], F); vec_GF2E s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_GF2 tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) { GF2 r; ProjectedInnerProduct(r, H.H[j].rep, tt); x.put(i*m + j, r); } if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_GF2& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F, const vec_GF2& proj) { if (a.length() > F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); GF2EXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m, const vec_GF2E& R, const vec_GF2& proj) { vec_GF2 x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*GF2E::degree()) LogicError("ProbMinPoly: bad args"); vec_GF2E R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_GF2 proj; PrecomputeProj(proj, GF2E::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m, const vec_GF2& proj) { long n = F.n; if (m < 1 || m > n*GF2E::degree()) LogicError("ProbMinPoly: bad args"); vec_GF2E R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(GF2X& hh, const GF2EX& g, const GF2EXModulus& F, long m) { GF2X h; GF2EX h1; long n = F.n; if (m < 1 || m > n*GF2E::degree()) { LogicError("MinPoly: bad args"); } vec_GF2 proj; PrecomputeProj(proj, GF2E::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; GF2X h2; GF2EX h3; vec_GF2E R; GF2EXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m) { if (m < 1 || m > deg(F)*GF2E::degree()) LogicError("IrredPoly: bad args"); vec_GF2E R; R.SetLength(1); R[0] = 1; vec_GF2 proj; proj.SetLength(1); proj.put(0, 1); DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-11.5.1/src/GF2EXFactoring.cpp0000644417616742025610000011122414064716022020121 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_START_IMPL static void IterSqr(GF2E& c, const GF2E& a, long n) { GF2E res; long i; res = a; for (i = 0; i < n; i++) sqr(res, res); c = res; } void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& ff) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SquareFreeDecomp: bad args"); GF2EX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a square */ long k, d; d = deg(r)/2; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterSqr(f.rep[k], r.rep[k*2], GF2E::degree()-1); m = m*2; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_GF2XVec& M, long verbose) { long k, l, n; long i, j; long pos; GF2X t1, t2; GF2X *x, *y; const GF2XModulus& p = GF2E::modulus(); n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p, and make row l reduced InvMod(t1, M[l][k], p); for (j = k+1; j < n; j++) { rem(t2, M[l][j], p); MulMod(M[l][j], t2, t1, p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(vec_GF2XVec& M, long n, const GF2EX& g, const GF2EXModulus& F, long verbose) { long i, j, m; GF2EX h; M.SetLength(n); for (i = 0; i < n; i++) M[i].SetSize(n, 2*GF2E::WordLength()); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = rep(h.rep[i]); else clear(M[i][j]); } if (j < n-1) MulMod(h, h, g, F); } for (i = 0; i < n; i++) add(M[i][i], M[i][i], 1); } static void TraceMap(GF2EX& h, const GF2EX& a, const GF2EXModulus& F) // one could consider making a version based on modular composition, // as in ComposeFrobeniusMap... { GF2EX res, tmp; res = a; tmp = a; long i; for (i = 0; i < GF2E::degree()-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void PlainFrobeniusMap(GF2EX& h, const GF2EXModulus& F) { GF2EX res; SetX(res); long i; for (i = 0; i < GF2E::degree(); i++) SqrMod(res, res, F); h = res; } long UseComposeFrobenius(long d, long n) { long i; i = 1; while (i <= d) i = i << 1; i = i >> 1; i = i >> 1; long m = 1; long dz; if (n == 2) { dz = 1; } else { while (i) { long m1 = 2*m; if (i & d) m1++; if (m1 >= NTL_BITS_PER_LONG-1 || (1L << m1) >= n) break; m = m1; i = i >> 1; } dz = 1L << m; } long rootn = SqrRoot(n); long cnt = 0; if (i) { cnt += SqrRoot(dz+1); i = i >> 1; } while (i) { cnt += rootn; i = i >> 1; } return 4*cnt <= d; } void ComposeFrobeniusMap(GF2EX& y, const GF2EXModulus& F) { long d = GF2E::degree(); long n = deg(F); long i; i = 1; while (i <= d) i = i << 1; i = i >> 1; GF2EX z(INIT_SIZE, n), z1(INIT_SIZE, n); i = i >> 1; long m = 1; if (n == 2) { SetX(z); SqrMod(z, z, F); } else { while (i) { long m1 = 2*m; if (i & d) m1++; if (m1 >= NTL_BITS_PER_LONG-1 || (1L << m1) >= n) break; m = m1; i = i >> 1; } clear(z); SetCoeff(z, 1L << m); } while (i) { z1 = z; long j, k, dz; dz = deg(z); for (j = 0; j <= dz; j++) for (k = 0; k < m; k++) sqr(z1.rep[j], z1.rep[j]); CompMod(z, z1, z, F); m = 2*m; if (d & i) { SqrMod(z, z, F); m++; } i = i >> 1; } y = z; } void FrobeniusMap(GF2EX& h, const GF2EXModulus& F) { long n = deg(F); long d = GF2E::degree(); if (n == 1) { h = ConstTerm(F); return; } if (UseComposeFrobenius(d, n)) ComposeFrobeniusMap(h, F); else PlainFrobeniusMap(h, F); } static void RecFindRoots(vec_GF2E& x, const GF2EX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); x[k] = ConstTerm(f); return; } GF2EX h; GF2E r; { GF2EXModulus F; build(F, f); do { random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_GF2E& x, const GF2EX& ff) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(GF2EX& g, const vec_long& D, const vec_GF2XVec& M) { GF2X t1, t2; long n = D.length(); long i, j, s; g.rep.SetLength(n); vec_GF2E& v = g.rep; for (j = n-1; j >= 0; j--) { if (D[j] == -1) random(v[j]); else { i = D[j]; // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s] clear(t1); for (s = j+1; s < n; s++) { mul(t2, rep(v[s]), M[i][s]); add(t1, t1, t2); } conv(v[j], t1); } } g.normalize(); } static void split(GF2EX& f1, GF2EX& g1, GF2EX& f2, GF2EX& g2, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots, long lo, long mid) { long r = mid-lo+1; GF2EXModulus F; build(F, f); vec_GF2E lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; GF2EX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } GF2EX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_GF2EX& factors, const GF2EX& f, const GF2EX& g, const vec_GF2E& roots) { long r = roots.length(); long i; GF2EX h; factors.SetLength(r); for (i = 0; i < r; i++) { add(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_GF2EX& factors, const GF2EX& ff, long verbose) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; long n = deg(f); GF2EXModulus F; build(F, f); GF2EX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(g, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_long D; long r; vec_GF2XVec M; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } NullSpace(r, D, M, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_GF2E roots; RandomBasisElt(g, D, M); MinPolyMod(h, g, F, r); if (deg(h) == r) M.kill(); FindRoots(roots, h); FindFactors(factors, f, g, roots); GF2EX g1; vec_GF2EX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, D, M); S.kill(); for (i = 0; i < factors.length(); i++) { const GF2EX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose) { double t; vec_pair_GF2EX_long sfd; vec_GF2EX x; if (!IsOne(LeadCoeff(f))) LogicError("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_GF2EX_long& factors, const GF2EX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(GF2EX& f, vec_pair_GF2EX_long& factors, const GF2EXModulus& F, long limit, const vec_GF2EX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; GF2EX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); GF2EX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b) { if (d < 0) LogicError("TraceMap: bad args"); GF2EX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(GF2EX& y, const GF2EX& h, long q, const GF2EXModulus& F) { if (q < 0) LogicError("powerCompose: bad args"); GF2EX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const GF2EX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; GF2EXModulus F; build(F, f); GF2EX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_CHEAP_THREAD_LOCAL long GF2EX_BlockingFactor = 10; void DDF(vec_pair_GF2EX_long& factors, const GF2EX& ff, const GF2EX& hh, long verbose) { GF2EX f = ff; GF2EX h = hh; if (!IsOne(LeadCoeff(f))) LogicError("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = GF2EX_BlockingFactor; GF2EXModulus F; build(F, f); GF2EXArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; GF2EX g, X; vec_GF2EX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); add(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose) { vec_GF2E roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); add(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_GF2EX& v, const GF2EX& f, const GF2EX& b, long d) { GF2EX a, g, h; GF2EXModulus F; vec_GF2E roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& b, long d, long verbose) { vec_GF2EX v; long i; GF2EX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { GF2EX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_GF2EX& factors, const GF2EX& ff, const GF2EX& bb, long d, long verbose) { GF2EX f = ff; GF2EX b = bb; if (!IsOne(LeadCoeff(f))) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_GF2EX& factors, const GF2EX& ff, long verbose) { GF2EX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; GF2EXModulus F; build(F, f); GF2EX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_GF2EX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } GF2EX hh; vec_GF2EX v; long i; for (i = 0; i < u.length(); i++) { const GF2EX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("CanZass: bad args"); double t; vec_pair_GF2EX_long sfd; vec_GF2EX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(GF2EX& f, const vec_pair_GF2EX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); GF2EX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const GF2EX& h, long q, long a, const GF2EXModulus& F) { long b, e; GF2EX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } static void TandemPowerCompose(GF2EX& y1, GF2EX& y2, const GF2EX& h, long q1, long q2, const GF2EXModulus& F) { GF2EX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } static long RecComputeDegree(long u, const GF2EX& h, const GF2EXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); GF2EX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(GF2E& root, const GF2EX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { GF2EXModulus F; GF2EX h, h1, f; GF2E r; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } root = ConstTerm(f); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const GF2EX& h, long q, long a, const GF2EXModulus& F) { long e; GF2EX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); add(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const GF2EX& h, const GF2EXModulus& F, const FacVec& fvec) { long q1, q2; GF2EX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const GF2EX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; GF2EXModulus F; build(F, f); GF2EX h; FrobeniusMap(h, F); GF2EX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const GF2EX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; GF2EXModulus F; build(F, f); GF2EX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); GF2EXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; GF2EX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { add(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_GF2EX& h, const GF2EX& f, const GF2EX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { GF2EX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); add(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); add(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(GF2EX& x, const GF2EX& f, const GF2EX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_GF2EX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_GF2E a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(GF2EX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(GF2EX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { GF2EX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(GF2EX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(GF2EX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } GF2EX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(GF2EX& f, const GF2EX& g) { GF2EXModulus G; GF2EX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_CHEAP_THREAD_LOCAL long GF2EX_GCDTableSize = 4; NTL_CHEAP_THREAD_LOCAL double GF2EXFileThresh = NTL_FILE_THRESH; static NTL_CHEAP_THREAD_LOCAL vec_GF2EX *BabyStepFile = 0; static NTL_CHEAP_THREAD_LOCAL vec_GF2EX *GiantStepFile = 0; static NTL_CHEAP_THREAD_LOCAL long use_files; static double CalcTableSize(long n, long k) { double sz = GF2E::storage(); sz = sz * n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_GF2E); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(GF2EX& h1, const GF2EX& f, const GF2EX& h, long k, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } GF2EXModulus F; build(F, f); GF2EXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; GF2XHexOutputPush push; GF2X::HexOutput = 1; if (!use_files) { (*BabyStepFile).SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("baby", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const GF2EX& f, const GF2EX& h, long l, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } GF2EXModulus F; build(F, f); GF2EXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); GF2EX h1; h1 = h; long i; GF2XHexOutputPush push; GF2X::HexOutput = 1; if (!use_files) { (*GiantStepFile).SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void NewAddFactor(vec_pair_GF2EX_long& u, const GF2EX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_GF2EX_long& u, GF2EX& f, const GF2EXModulus& F, vec_GF2EX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; GF2EX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(GF2EX& g, long gs, const GF2EXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName("giant", gs)); NTL_INPUT_CHECK_ERR(s >> g); } else g = (*GiantStepFile)(gs); rem(g, g, F); } static void FetchBabySteps(vec_GF2EX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName("baby", i)); NTL_INPUT_CHECK_ERR(s >> v[i]); } else v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_GF2EX_long& u, const GF2EX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_GF2EX BabyStep; FetchBabySteps(BabyStep, k); vec_GF2EX buf(INIT_SIZE, GF2EX_GCDTableSize); GF2EX f; f = ff; GF2EXModulus F; build(F, f); GF2EX g; GF2EX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); add(buf[size-1], g, BabyStep[bs]); } else { add(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == GF2EX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_GF2EX_long& factors, const GF2EX& ff, long k, long gs, const vec_GF2EX& BabyStep, long verbose) { vec_GF2EX buf(INIT_SIZE, GF2EX_GCDTableSize); GF2EX f; f = ff; GF2EXModulus F; build(F, f); GF2EX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); add(buf[size], buf[size], g); size++; if (size == GF2EX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_GF2EX_long& factors, const vec_pair_GF2EX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_GF2EX BabyStep; long i; for (i = 0; i < u.length(); i++) { const GF2EX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; GF2EX h1; if (CalcTableSize(deg(f), k + l - 1) > GF2EXFileThresh) use_files = 1; else use_files = 0; FileList flist; vec_GF2EX local_BabyStepFile; vec_GF2EX local_GiantStepFile; BabyStepFile = &local_BabyStepFile; GiantStepFile = &local_GiantStepFile; GenerateBabySteps(h1, f, h, k, flist, verbose); GenerateGiantSteps(f, h1, l, flist, verbose); vec_pair_GF2EX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); } long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; GF2EXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); GF2EX h1; h1 = h; vec_GF2EX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-11.5.1/src/GF2X.cpp0000644417616742025610000012064014064716022016161 0ustar gid-shoupvpug-gid-shoupv #include #include #include #if (defined(NTL_WIZARD_HACK) && defined(NTL_GF2X_LIB)) #undef NTL_GF2X_LIB #endif #ifdef NTL_GF2X_LIB #include #endif #ifdef NTL_HAVE_PCLMUL #include #define NTL_INLINE inline static inline void pclmul_mul1 (unsigned long *c, unsigned long a, unsigned long b) { __m128i aa = _mm_setr_epi64( _mm_cvtsi64_m64(a), _mm_cvtsi64_m64(0)); __m128i bb = _mm_setr_epi64( _mm_cvtsi64_m64(b), _mm_cvtsi64_m64(0)); _mm_storeu_si128((__m128i*)c, _mm_clmulepi64_si128(aa, bb, 0)); } #else #define NTL_INLINE #endif NTL_START_IMPL NTL_CHEAP_THREAD_LOCAL long GF2X::HexOutput = 0; void GF2X::SetMaxLength(long n) { if (n < 0) LogicError("GF2X::SetMaxLength: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("GF2X::SetMaxLength: excessive length"); long w = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; xrep.SetMaxLength(w); } GF2X::GF2X(INIT_SIZE_TYPE, long n) { SetMaxLength(n); } const GF2X& GF2X::zero() { static const GF2X z; // GLOBAL (assumes C++11 thread-safe init) return z; } void GF2X::normalize() { long n; const _ntl_ulong *p; n = xrep.length(); if (n == 0) return; p = xrep.elts() + n; while (n > 0 && (*--p) == 0) { n--; } xrep.QuickSetLength(n); } void GF2X::SetLength(long n) { if (n < 0) { LogicError("SetLength: negative index"); return; // NOTE: this helps the compiler optimize } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("GF2X::SetLength: excessive length"); long w = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long old_w = xrep.length(); xrep.SetLength(w); long i; if (w > old_w) { // zero out new words for (i = old_w; i < w; i++) xrep[i] = 0; } else { // zero out high order bits of last word long wi = n/NTL_BITS_PER_LONG; long bi = n - wi*NTL_BITS_PER_LONG; if (bi == 0) return; unsigned long mask = (1UL << bi) - 1UL; xrep[wi] &= mask; } } long IsZero(const GF2X& a) { return a.xrep.length() == 0; } long IsOne(const GF2X& a) { return a.xrep.length() == 1 && a.xrep[0] == 1; } long IsX(const GF2X& a) { return a.xrep.length() == 1 && a.xrep[0] == 2; } const GF2 coeff(const GF2X& a, long i) { if (i < 0) return to_GF2(0); long wi = i/NTL_BITS_PER_LONG; if (wi >= a.xrep.length()) return to_GF2(0); long bi = i - wi*NTL_BITS_PER_LONG; return to_GF2((a.xrep[wi] & (1UL << bi)) != 0); } const GF2 LeadCoeff(const GF2X& a) { if (IsZero(a)) return to_GF2(0); else return to_GF2(1); } const GF2 ConstTerm(const GF2X& a) { if (IsZero(a)) return to_GF2(0); else return to_GF2((a.xrep[0] & 1) != 0); } void set(GF2X& x) { x.xrep.SetLength(1); x.xrep[0] = 1; } void SetX(GF2X& x) { x.xrep.SetLength(1); x.xrep[0] = 2; } void SetCoeff(GF2X& x, long i) { if (i < 0) { LogicError("SetCoeff: negative index"); return; // NOTE: helpse the compiler optimize } long n, j; n = x.xrep.length(); long wi = i/NTL_BITS_PER_LONG; if (wi >= n) { x.xrep.SetLength(wi+1); for (j = n; j <= wi; j++) x.xrep[j] = 0; } long bi = i - wi*NTL_BITS_PER_LONG; x.xrep[wi] |= (1UL << bi); } void SetCoeff(GF2X& x, long i, long val) { if (i < 0) { LogicError("SetCoeff: negative index"); return; // NOTE: helps the compiler optimize } val = val & 1; if (val) { SetCoeff(x, i); return; } // we want to clear position i long n; n = x.xrep.length(); long wi = i/NTL_BITS_PER_LONG; if (wi >= n) return; long bi = i - wi*NTL_BITS_PER_LONG; x.xrep[wi] &= ~(1UL << bi); if (wi == n-1 && !x.xrep[wi]) x.normalize(); } void SetCoeff(GF2X& x, long i, GF2 a) { SetCoeff(x, i, rep(a)); } long deg(const GF2X& aa) { long n = aa.xrep.length(); if (n == 0) return -1; _ntl_ulong a = aa.xrep[n-1]; if (a == 0) LogicError("GF2X: unnormalized polynomial detected in deg"); return NTL_BITS_PER_LONG*(n-1) + _ntl_count_bits(a) - 1; #if 0 long i = 0; while (a>=256) i += 8, a >>= 8; if (a >=16) i += 4, a >>= 4; if (a >= 4) i += 2, a >>= 2; if (a >= 2) i += 2; else if (a >= 1) i++; #endif } long operator==(const GF2X& a, const GF2X& b) { return a.xrep == b.xrep; } long operator==(const GF2X& a, long b) { if (b & 1) return IsOne(a); else return IsZero(a); } long operator==(const GF2X& a, GF2 b) { if (b == 1) return IsOne(a); else return IsZero(a); } static istream & HexInput(istream& s, GF2X& a) { long n; long c; long i; long val; GF2X ibuf; n = 0; clear(ibuf); c = s.peek(); val = CharToIntVal(c); while (val != -1) { for (i = 0; i < 4; i++) if (val & (1L << i)) SetCoeff(ibuf, n+i); n += 4; s.get(); c = s.peek(); val = CharToIntVal(c); } a = ibuf; return s; } istream & operator>>(istream& s, GF2X& a) { NTL_ZZRegister(ival); long c; if (!s) NTL_INPUT_ERROR(s, "bad GF2X input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '0') { s.get(); c = s.peek(); if (c == 'x' || c == 'X') { s.get(); return HexInput(s, a); } else { NTL_INPUT_ERROR(s, "bad GF2X input"); } } if (c != '[') { NTL_INPUT_ERROR(s, "bad GF2X input"); } GF2X ibuf; long n; n = 0; clear(ibuf); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (!(s >> ival)) NTL_INPUT_ERROR(s, "bad GF2X input"); SetCoeff(ibuf, n, to_GF2(ival)); n++; c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) NTL_INPUT_ERROR(s, "bad GF2X input"); s.get(); a = ibuf; return s; } static ostream & HexOutput(ostream& s, const GF2X& a) { s << "0x"; long da = deg(a); if (da < 0) { s << '0'; return s; } long i, n, val; val = 0; n = 0; for (i = 0; i <= da; i++) { val = val | (rep(coeff(a, i)) << n); n++; if (n == 4) { s << IntValToChar(val); val = 0; n = 0; } } if (val) s << IntValToChar(val); return s; } ostream& operator<<(ostream& s, const GF2X& a) { if (GF2X::HexOutput) return HexOutput(s, a); long i, da; GF2 c; da = deg(a); s << '['; for (i = 0; i <= da; i++) { c = coeff(a, i); if (c == 0) s << "0"; else s << "1"; if (i < da) s << " "; } s << ']'; return s; } void random(GF2X& x, long n) { if (n < 0) LogicError("GF2X random: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("GF2X random: excessive length"); long wl = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; x.xrep.SetLength(wl); VectorRandomWord(wl-1, x.xrep.elts()); if (n > 0) { long pos = n % NTL_BITS_PER_LONG; if (pos == 0) pos = NTL_BITS_PER_LONG; x.xrep[wl-1] = RandomBits_ulong(pos); } x.normalize(); } void add(GF2X& x, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); long i; if (sa == sb) { x.xrep.SetLength(sa); if (sa == 0) return; _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; i = sa-1; while (i >= 0 && !xp[i]) i--; x.xrep.QuickSetLength(i+1); } else if (sa < sb) { x.xrep.SetLength(sb); _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sa; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sb; i++) xp[i] = bp[i]; } else { // sa > sb x.xrep.SetLength(sa); _ntl_ulong *xp = x.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); for (i = 0; i < sb; i++) xp[i] = ap[i] ^ bp[i]; for (; i < sa; i++) xp[i] = ap[i]; } } /* * The bodies of mul1, Mul1, AddMul1, and mul_half * are generated by the MakeDesc program, and the * macros NTL_BB_MUL_CODE... are defined in mach_desc.h. * Thanks to Paul Zimmermann for providing improvements * to this approach. */ #if (defined(NTL_GF2X_ALTCODE1)) #define NTL_EFF_BB_MUL_CODE0 NTL_ALT1_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_ALT1_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_ALT1_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_ALT1_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_ALT1_HALF_BB_MUL_CODE0 #elif (defined(NTL_GF2X_ALTCODE)) #define NTL_EFF_BB_MUL_CODE0 NTL_ALT_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_ALT_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_ALT_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_ALT_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_ALT_HALF_BB_MUL_CODE0 #else #define NTL_EFF_BB_MUL_CODE0 NTL_BB_MUL_CODE0 #define NTL_EFF_BB_MUL_CODE1 NTL_BB_MUL_CODE1 #define NTL_EFF_BB_MUL_CODE2 NTL_BB_MUL_CODE2 #define NTL_EFF_SHORT_BB_MUL_CODE1 NTL_SHORT_BB_MUL_CODE1 #define NTL_EFF_HALF_BB_MUL_CODE0 NTL_HALF_BB_MUL_CODE0 #endif static NTL_INLINE void mul1(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { #ifdef NTL_HAVE_PCLMUL pclmul_mul1(c, a, b); #else NTL_EFF_BB_MUL_CODE0 #endif } #ifdef NTL_GF2X_NOINLINE #define mul1_IL mul1 #else static inline void mul1_inline(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { #ifdef NTL_HAVE_PCLMUL pclmul_mul1(c, a, b); #else NTL_EFF_BB_MUL_CODE0 #endif } #define mul1_IL mul1_inline #endif static void Mul1(_ntl_ulong *cp, const _ntl_ulong *bp, long sb, _ntl_ulong a) { #ifdef NTL_HAVE_PCLMUL long i; unsigned long carry, prod[2]; carry = 0; for (i = 0; i < sb; i++) { pclmul_mul1(prod, bp[i], a); cp[i] = carry ^ prod[0]; carry = prod[1]; } cp[sb] = carry; #else NTL_EFF_BB_MUL_CODE1 #endif // warning #13200: No EMMS instruction before return } static void AddMul1(_ntl_ulong *cp, const _ntl_ulong* bp, long sb, _ntl_ulong a) { #ifdef NTL_HAVE_PCLMUL long i; unsigned long carry, prod[2]; carry = 0; for (i = 0; i < sb; i++) { pclmul_mul1(prod, bp[i], a); cp[i] ^= carry ^ prod[0]; carry = prod[1]; } cp[sb] ^= carry; #else NTL_EFF_BB_MUL_CODE2 #endif } static void Mul1_short(_ntl_ulong *cp, const _ntl_ulong *bp, long sb, _ntl_ulong a) { #ifdef NTL_HAVE_PCLMUL long i; unsigned long carry, prod[2]; carry = 0; for (i = 0; i < sb; i++) { pclmul_mul1(prod, bp[i], a); cp[i] = carry ^ prod[0]; carry = prod[1]; } cp[sb] = carry; #else NTL_EFF_SHORT_BB_MUL_CODE1 #endif // warning #13200: No EMMS instruction before return } static void mul_half(_ntl_ulong *c, _ntl_ulong a, _ntl_ulong b) { #ifdef NTL_HAVE_PCLMUL pclmul_mul1(c, a, b); #else NTL_EFF_HALF_BB_MUL_CODE0 #endif } // mul2...mul8 hard-code 2x2...8x8 word multiplies. // I adapted these routines from LiDIA (except mul3, see below). // NOTE: Generally, inlining these functions seems to hurt performance, // at least when using software mul1; for hardware mul1, I've // switched to making mul2, 3, 4 inline, although this should // really be profiled. static NTL_INLINE void mul2(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0, hs1; _ntl_ulong hl2[2]; hs0 = a[0] ^ a[1]; hs1 = b[0] ^ b[1]; mul1_IL(c, a[0], b[0]); mul1_IL(c+2, a[1], b[1]); mul1_IL(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[2]; hl2[1] = hl2[1] ^ c[1] ^ c[3]; c[1] ^= hl2[0]; c[2] ^= hl2[1]; } /* * This version of mul3 I got from Weimerskirch, Stebila, * and Shantz, "Generic GF(2^m) arithmetic in software * an its application to ECC" (ACISP 2003). */ static NTL_INLINE void mul3 (_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong d0[2], d1[2], d2[2], d01[2], d02[2], d12[2]; mul1_IL(d0, a[0], b[0]); mul1_IL(d1, a[1], b[1]); mul1_IL(d2, a[2], b[2]); mul1_IL(d01, a[0]^a[1], b[0]^b[1]); mul1_IL(d02, a[0]^a[2], b[0]^b[2]); mul1_IL(d12, a[1]^a[2], b[1]^b[2]); c[0] = d0[0]; c[1] = d0[1] ^ d01[0] ^ d1[0] ^ d0[0]; c[2] = d01[1] ^ d1[1] ^ d0[1] ^ d02[0] ^ d2[0] ^ d0[0] ^ d1[0]; c[3] = d02[1] ^ d2[1] ^ d0[1] ^ d1[1] ^ d12[0] ^ d1[0] ^ d2[0]; c[4] = d12[1] ^ d1[1] ^ d2[1] ^ d2[0]; c[5] = d2[1]; } static NTL_INLINE void mul4(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[2], hs1[2]; _ntl_ulong hl2[4]; hs0[0] = a[0] ^ a[2]; hs0[1] = a[1] ^ a[3]; hs1[0] = b[0] ^ b[2]; hs1[1] = b[1] ^ b[3]; mul2(c, a, b); mul2(c+4, a+2, b+2); mul2(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[4]; hl2[1] = hl2[1] ^ c[1] ^ c[5]; hl2[2] = hl2[2] ^ c[2] ^ c[6]; hl2[3] = hl2[3] ^ c[3] ^ c[7]; c[2] ^= hl2[0]; c[3] ^= hl2[1]; c[4] ^= hl2[2]; c[5] ^= hl2[3]; } static void mul5 (_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[3], hs1[3]; _ntl_ulong hl2[6]; hs0[0] = a[0] ^ a[3]; hs0[1] = a[1] ^ a[4]; hs0[2] = a[2]; hs1[0] = b[0] ^ b[3]; hs1[1] = b[1] ^ b[4]; hs1[2] = b[2]; mul3(c, a, b); mul3(hl2, hs0, hs1); mul2(c+6, a+3, b+3); hl2[0] = hl2[0] ^ c[0] ^ c[6]; hl2[1] = hl2[1] ^ c[1] ^ c[7]; hl2[2] = hl2[2] ^ c[2] ^ c[8]; hl2[3] = hl2[3] ^ c[3] ^ c[9]; hl2[4] = hl2[4] ^ c[4]; hl2[5] = hl2[5] ^ c[5]; c[3] ^= hl2[0]; c[4] ^= hl2[1]; c[5] ^= hl2[2]; c[6] ^= hl2[3]; c[7] ^= hl2[4]; c[8] ^= hl2[5]; // warning #13200: No EMMS instruction before return } static void mul6(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[3], hs1[3]; _ntl_ulong hl2[6]; hs0[0] = a[0] ^ a[3]; hs0[1] = a[1] ^ a[4]; hs0[2] = a[2] ^ a[5]; hs1[0] = b[0] ^ b[3]; hs1[1] = b[1] ^ b[4]; hs1[2] = b[2] ^ b[5]; mul3(c, a, b); mul3(c+6, a+3, b+3); mul3(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[6]; hl2[1] = hl2[1] ^ c[1] ^ c[7]; hl2[2] = hl2[2] ^ c[2] ^ c[8]; hl2[3] = hl2[3] ^ c[3] ^ c[9]; hl2[4] = hl2[4] ^ c[4] ^ c[10]; hl2[5] = hl2[5] ^ c[5] ^ c[11]; c[3] ^= hl2[0]; c[4] ^= hl2[1]; c[5] ^= hl2[2]; c[6] ^= hl2[3]; c[7] ^= hl2[4]; c[8] ^= hl2[5]; } static void mul7(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[4], hs1[4]; _ntl_ulong hl2[8]; hs0[0] = a[0] ^ a[4]; hs0[1] = a[1] ^ a[5]; hs0[2] = a[2] ^ a[6]; hs0[3] = a[3]; hs1[0] = b[0] ^ b[4]; hs1[1] = b[1] ^ b[5]; hs1[2] = b[2] ^ b[6]; hs1[3] = b[3]; mul4(c, a, b); mul4(hl2, hs0, hs1); mul3(c+8, a+4, b+4); hl2[0] = hl2[0] ^ c[0] ^ c[8]; hl2[1] = hl2[1] ^ c[1] ^ c[9]; hl2[2] = hl2[2] ^ c[2] ^ c[10]; hl2[3] = hl2[3] ^ c[3] ^ c[11]; hl2[4] = hl2[4] ^ c[4] ^ c[12]; hl2[5] = hl2[5] ^ c[5] ^ c[13]; hl2[6] = hl2[6] ^ c[6]; hl2[7] = hl2[7] ^ c[7]; c[4] ^= hl2[0]; c[5] ^= hl2[1]; c[6] ^= hl2[2]; c[7] ^= hl2[3]; c[8] ^= hl2[4]; c[9] ^= hl2[5]; c[10] ^= hl2[6]; c[11] ^= hl2[7]; // warning #13200: No EMMS instruction before return } static void mul8(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b) { _ntl_ulong hs0[4], hs1[4]; _ntl_ulong hl2[8]; hs0[0] = a[0] ^ a[4]; hs0[1] = a[1] ^ a[5]; hs0[2] = a[2] ^ a[6]; hs0[3] = a[3] ^ a[7]; hs1[0] = b[0] ^ b[4]; hs1[1] = b[1] ^ b[5]; hs1[2] = b[2] ^ b[6]; hs1[3] = b[3] ^ b[7]; mul4(c, a, b); mul4(c+8, a+4, b+4); mul4(hl2, hs0, hs1); hl2[0] = hl2[0] ^ c[0] ^ c[8]; hl2[1] = hl2[1] ^ c[1] ^ c[9]; hl2[2] = hl2[2] ^ c[2] ^ c[10]; hl2[3] = hl2[3] ^ c[3] ^ c[11]; hl2[4] = hl2[4] ^ c[4] ^ c[12]; hl2[5] = hl2[5] ^ c[5] ^ c[13]; hl2[6] = hl2[6] ^ c[6] ^ c[14]; hl2[7] = hl2[7] ^ c[7] ^ c[15]; c[4] ^= hl2[0]; c[5] ^= hl2[1]; c[6] ^= hl2[2]; c[7] ^= hl2[3]; c[8] ^= hl2[4]; c[9] ^= hl2[5]; c[10] ^= hl2[6]; c[11] ^= hl2[7]; // warning #13200: No EMMS instruction before return } static void KarMul(_ntl_ulong *c, const _ntl_ulong *a, const _ntl_ulong *b, long len, _ntl_ulong *stk) { if (len <= 8) { switch (len) { case 1: mul1(c, a[0], b[0]); break; case 2: mul2(c, a, b); break; case 3: mul3(c, a, b); break; case 4: mul4(c, a, b); break; case 5: mul5(c, a, b); break; case 6: mul6(c, a, b); break; case 7: mul7(c, a, b); break; case 8: mul8(c, a, b); break; } return; // warning #13200: No EMMS instruction before return } long ll, lh, i, ll2, lh2; const _ntl_ulong *a0, *a1, *b0, *b1; _ntl_ulong *a01, *b01, *h; lh = len >> 1; ll = (len+1) >> 1; ll2 = ll << 1; lh2 = lh << 1; a01 = stk; stk += ll+1; b01 = stk; stk += ll+1; h = stk; stk += ll2+1; a0 = a; a1 = a+ll; b0 = b; b1 = b+ll; KarMul(c, a0, b0, ll, stk); KarMul(c+ll2, a1, b1, lh, stk); for (i = 0; i < lh; i++) { a01[i] = a[i] ^ a[i+ll]; b01[i] = b[i] ^ b[i+ll]; } if (lh < ll) { a01[lh] = a[lh]; b01[lh] = b[lh]; } KarMul(h, a01, b01, ll, stk); for (i = 0; i < ll2; i++) h[i] ^= c[i]; for (i = 0; i < lh2; i++) h[i] ^= c[i+ll2]; for (i = 0; i < ll2; i++) c[i+ll] ^= h[i]; } #ifdef NTL_GF2X_LIB void mul(GF2X& c, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= 0 || sb <= 0) { clear(c); return; } _ntl_ulong a0 = a.xrep[0]; _ntl_ulong b0 = b.xrep[0]; if (sb == 1 && b0 == 1) { c = a; return; } if (sa == 1 && a0 == 1) { c = b; return; } if (&a == &b) { sqr(c, a); return; } // finally: the general case NTL_TLS_LOCAL(WordVector, mem); WordVectorWatcher watch_mem(mem); const _ntl_ulong *ap = a.xrep.elts(), *bp = b.xrep.elts(); _ntl_ulong *cp; long sc = sa + sb; long in_mem = 0; if (&a == &c || &b == &c) { mem.SetLength(sc); cp = mem.elts(); in_mem = 1; } else { c.xrep.SetLength(sc); cp = c.xrep.elts(); } // This is thread safe in v1.2 of gf2x gf2x_mul(cp, ap, sa, bp, sb); if (in_mem) { c.xrep = mem; } c.normalize(); } #else void OldMul(GF2X& c, const GF2X& a, const GF2X& b) { mul(c, a, b); } #endif #ifdef NTL_GF2X_LIB void OldMul(GF2X& c, const GF2X& a, const GF2X& b) #else void mul(GF2X& c, const GF2X& a, const GF2X& b) #endif { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= 0 || sb <= 0) { clear(c); return; } _ntl_ulong a0 = a.xrep[0]; _ntl_ulong b0 = b.xrep[0]; if (sb == 1 && b0 == 1) { c = a; return; } if (sa == 1 && a0 == 1) { c = b; return; } if (&a == &b) { sqr(c, a); return; } if (sa == sb && sa <= 8) { // we treat these cases specially for efficiency reasons switch (sa) { case 1: { _ntl_ulong v[2]; if (!(a0 >> NTL_BITS_PER_LONG/2)) mul_half(v, b0, a0); else if (!(b0 >> NTL_BITS_PER_LONG/2)) mul_half(v, a0, b0); else mul1(v, a0, b0); if (v[1]) { c.xrep.SetLength(2); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; } else { c.xrep.SetLength(1); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; } } return; case 2: { _ntl_ulong v[4]; mul2(v, &a.xrep[0], &b.xrep[0]); if (v[3]) { c.xrep.SetLength(4); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; } else { c.xrep.SetLength(3); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; } } return; case 3: { _ntl_ulong v[6]; mul3(v, &a.xrep[0], &b.xrep[0]); if (v[5]) { c.xrep.SetLength(6); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; } else { c.xrep.SetLength(5); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; } } return; case 4: { _ntl_ulong v[8]; mul4(v, &a.xrep[0], &b.xrep[0]); if (v[7]) { c.xrep.SetLength(8); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; } else { c.xrep.SetLength(7); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; } } return; case 5: { _ntl_ulong v[10]; mul5(v, &a.xrep[0], &b.xrep[0]); if (v[9]) { c.xrep.SetLength(10); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; } else { c.xrep.SetLength(9); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; } } return; case 6: { _ntl_ulong v[12]; mul6(v, &a.xrep[0], &b.xrep[0]); if (v[11]) { c.xrep.SetLength(12); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; } else { c.xrep.SetLength(11); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; } } // warning #13200: No EMMS instruction before return return; case 7: { _ntl_ulong v[14]; mul7(v, &a.xrep[0], &b.xrep[0]); if (v[13]) { c.xrep.SetLength(14); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; } else { c.xrep.SetLength(13); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; } } return; case 8: { _ntl_ulong v[16]; mul8(v, &a.xrep[0], &b.xrep[0]); if (v[15]) { c.xrep.SetLength(16); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; cp[14] = v[14]; cp[15] = v[15]; } else { c.xrep.SetLength(15); _ntl_ulong *cp = &c.xrep[0]; cp[0] = v[0]; cp[1] = v[1]; cp[2] = v[2]; cp[3] = v[3]; cp[4] = v[4]; cp[5] = v[5]; cp[6] = v[6]; cp[7] = v[7]; cp[8] = v[8]; cp[9] = v[9]; cp[10] = v[10]; cp[11] = v[11]; cp[12] = v[12]; cp[13] = v[13]; cp[14] = v[14]; } } return; } } // another special case: one of the two inputs // has length 1 (or less). if (sa == 1) { c.xrep.SetLength(sb + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *bp = b.xrep.elts(); if (a0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, bp, sb, a0); else Mul1_short(cp, bp, sb, a0); c.normalize(); return; } if (sb == 1) { c.xrep.SetLength(sa + 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); if (b0 >> (NTL_BITS_PER_LONG-NTL_BB_MUL1_BITS+1)) Mul1(cp, ap, sa, b0); else Mul1_short(cp, ap, sa, b0); c.normalize(); return; } // finally: the general case NTL_TLS_LOCAL(WordVector, mem); NTL_TLS_LOCAL(WordVector, stk); NTL_TLS_LOCAL(WordVector, vec); WordVectorWatcher watch_mem(mem); WordVectorWatcher watch_stk(stk); WordVectorWatcher watch_vec(vec); const _ntl_ulong *ap, *bp; _ntl_ulong *cp; long sc = sa + sb; long in_mem = 0; if (&a == &c || &b == &c) { mem.SetLength(sc); cp = mem.elts(); in_mem = 1; } else { c.xrep.SetLength(sc); cp = c.xrep.elts(); } long n, hn, sp; n = min(sa, sb); sp = 0; while (n > 8) { hn = (n+1) >> 1; sp += (hn << 2) + 3; n = hn; } stk.SetLength(sp); _ntl_ulong *stk_p = stk.elts(); if (sa > sb) { { long t; t = sa; sa = sb; sb = t; } ap = b.xrep.elts(); bp = a.xrep.elts(); } else { ap = a.xrep.elts(); bp = b.xrep.elts(); } vec.SetLength(2*sa); _ntl_ulong *v = vec.elts(); long i, j; for (i = 0; i < sc; i++) cp[i] = 0; do { if (sa == 0) break; if (sa == 1) { AddMul1(cp, bp, sb, ap[0]); break; } // general case for (i = 0; i+sa <= sb; i += sa) { KarMul(v, ap, bp + i, sa, stk_p); for (j = 0; j < 2*sa; j++) cp[i+j] ^= v[j]; } { const _ntl_ulong *t; t = ap; ap = bp + i; bp = t; } { long t; t = sa; sa = sb - i; sb = t; } cp = cp + i; } while (1); if (in_mem) c.xrep = mem; c.normalize(); } void mul(GF2X& c, const GF2X& a, long b) { if (b & 1) c = a; else clear(c); } void mul(GF2X& c, const GF2X& a, GF2 b) { if (b == 1) c = a; else clear(c); } void trunc(GF2X& x, const GF2X& a, long m) { if (m < 0) LogicError("trunc: bad args"); long n = a.xrep.length(); if (n == 0 || m == 0) { clear(x); return; } if (&x == &a) { if (n*NTL_BITS_PER_LONG > m) { long wm = (m-1)/NTL_BITS_PER_LONG; long bm = m - NTL_BITS_PER_LONG*wm; _ntl_ulong msk; if (bm == NTL_BITS_PER_LONG) msk = ~(0UL); else msk = ((1UL << bm) - 1UL); x.xrep[wm] &= msk; x.xrep.QuickSetLength(wm+1); x.normalize(); } } else if (n*NTL_BITS_PER_LONG <= m) x = a; else { long wm = (m-1)/NTL_BITS_PER_LONG; long bm = m - NTL_BITS_PER_LONG*wm; x.xrep.SetLength(wm+1); _ntl_ulong *xp = &x.xrep[0]; const _ntl_ulong *ap = &a.xrep[0]; long i; for (i = 0; i < wm; i++) xp[i] = ap[i]; _ntl_ulong msk; if (bm == NTL_BITS_PER_LONG) msk = ~(0UL); else msk = ((1UL << bm) - 1UL); xp[wm] = ap[wm] & msk; x.normalize(); } } void MulByX(GF2X& x, const GF2X& a) { long n = a.xrep.length(); if (n == 0) { clear(x); return; } if (a.xrep[n-1] & (1UL << (NTL_BITS_PER_LONG-1))) { x.xrep.SetLength(n+1); x.xrep[n] = 1; } else if (&x != &a) x.xrep.SetLength(n); _ntl_ulong *xp = &x.xrep[0]; const _ntl_ulong *ap = &a.xrep[0]; long i; for (i = n-1; i > 0; i--) xp[i] = (ap[i] << 1) | (ap[i-1] >> (NTL_BITS_PER_LONG-1)); xp[0] = ap[0] << 1; // no need to normalize } static const _ntl_ulong sqrtab[256] = { 0UL, 1UL, 4UL, 5UL, 16UL, 17UL, 20UL, 21UL, 64UL, 65UL, 68UL, 69UL, 80UL, 81UL, 84UL, 85UL, 256UL, 257UL, 260UL, 261UL, 272UL, 273UL, 276UL, 277UL, 320UL, 321UL, 324UL, 325UL, 336UL, 337UL, 340UL, 341UL, 1024UL, 1025UL, 1028UL, 1029UL, 1040UL, 1041UL, 1044UL, 1045UL, 1088UL, 1089UL, 1092UL, 1093UL, 1104UL, 1105UL, 1108UL, 1109UL, 1280UL, 1281UL, 1284UL, 1285UL, 1296UL, 1297UL, 1300UL, 1301UL, 1344UL, 1345UL, 1348UL, 1349UL, 1360UL, 1361UL, 1364UL, 1365UL, 4096UL, 4097UL, 4100UL, 4101UL, 4112UL, 4113UL, 4116UL, 4117UL, 4160UL, 4161UL, 4164UL, 4165UL, 4176UL, 4177UL, 4180UL, 4181UL, 4352UL, 4353UL, 4356UL, 4357UL, 4368UL, 4369UL, 4372UL, 4373UL, 4416UL, 4417UL, 4420UL, 4421UL, 4432UL, 4433UL, 4436UL, 4437UL, 5120UL, 5121UL, 5124UL, 5125UL, 5136UL, 5137UL, 5140UL, 5141UL, 5184UL, 5185UL, 5188UL, 5189UL, 5200UL, 5201UL, 5204UL, 5205UL, 5376UL, 5377UL, 5380UL, 5381UL, 5392UL, 5393UL, 5396UL, 5397UL, 5440UL, 5441UL, 5444UL, 5445UL, 5456UL, 5457UL, 5460UL, 5461UL, 16384UL, 16385UL, 16388UL, 16389UL, 16400UL, 16401UL, 16404UL, 16405UL, 16448UL, 16449UL, 16452UL, 16453UL, 16464UL, 16465UL, 16468UL, 16469UL, 16640UL, 16641UL, 16644UL, 16645UL, 16656UL, 16657UL, 16660UL, 16661UL, 16704UL, 16705UL, 16708UL, 16709UL, 16720UL, 16721UL, 16724UL, 16725UL, 17408UL, 17409UL, 17412UL, 17413UL, 17424UL, 17425UL, 17428UL, 17429UL, 17472UL, 17473UL, 17476UL, 17477UL, 17488UL, 17489UL, 17492UL, 17493UL, 17664UL, 17665UL, 17668UL, 17669UL, 17680UL, 17681UL, 17684UL, 17685UL, 17728UL, 17729UL, 17732UL, 17733UL, 17744UL, 17745UL, 17748UL, 17749UL, 20480UL, 20481UL, 20484UL, 20485UL, 20496UL, 20497UL, 20500UL, 20501UL, 20544UL, 20545UL, 20548UL, 20549UL, 20560UL, 20561UL, 20564UL, 20565UL, 20736UL, 20737UL, 20740UL, 20741UL, 20752UL, 20753UL, 20756UL, 20757UL, 20800UL, 20801UL, 20804UL, 20805UL, 20816UL, 20817UL, 20820UL, 20821UL, 21504UL, 21505UL, 21508UL, 21509UL, 21520UL, 21521UL, 21524UL, 21525UL, 21568UL, 21569UL, 21572UL, 21573UL, 21584UL, 21585UL, 21588UL, 21589UL, 21760UL, 21761UL, 21764UL, 21765UL, 21776UL, 21777UL, 21780UL, 21781UL, 21824UL, 21825UL, 21828UL, 21829UL, 21840UL, 21841UL, 21844UL, 21845UL }; static inline void sqr1(_ntl_ulong *c, _ntl_ulong a) { #ifdef NTL_HAVE_PCLMUL // this appears to be marginally faster than the // table-driven code pclmul_mul1(c, a, a); #else _ntl_ulong hi, lo; NTL_BB_SQR_CODE c[0] = lo; c[1] = hi; #endif } void sqr(GF2X& c, const GF2X& a) { long sa = a.xrep.length(); if (sa <= 0) { clear(c); return; } c.xrep.SetLength(sa << 1); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; for (i = sa-1; i >= 0; i--) sqr1(cp + (i << 1), ap[i]); c.normalize(); return; } void LeftShift(GF2X& c, const GF2X& a, long n) { if (IsZero(a)) { clear(c); return; } if (n == 1) { MulByX(c, a); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(c); else RightShift(c, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); if (n == 0) { c = a; return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sc = sa + wn; if (bn) sc++; c.xrep.SetLength(sc); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] = ap[i-wn]; for (i = wn-1; i >= 0; i--) cp[i] = 0; } else { cp[sa+wn] = ap[sa-1] >> (NTL_BITS_PER_LONG-bn); for (i = sa+wn-1; i >= wn+1; i--) cp[i] = (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] = ap[0] << bn; for (i = wn-1; i >= 0; i--) cp[i] = 0; } c.normalize(); } void ShiftAdd(GF2X& c, const GF2X& a, long n) // c = c + a*X^n { if (n < 0) LogicError("ShiftAdd: negative argument"); if (n == 0) { add(c, c, a); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in ShiftAdd"); long sa = a.xrep.length(); if (sa <= 0) { return; } long sc = c.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long ss = sa + wn; if (bn) ss++; if (ss > sc) c.xrep.SetLength(ss); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; for (i = sc; i < ss; i++) cp[i] = 0; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] ^= ap[i-wn]; } else { cp[sa+wn] ^= ap[sa-1] >> (NTL_BITS_PER_LONG-bn); for (i = sa+wn-1; i >= wn+1; i--) cp[i] ^= (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] ^= ap[0] << bn; } c.normalize(); } void RightShift(GF2X& c, const GF2X& a, long n) { if (IsZero(a)) { clear(c); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(c, a, -n); return; } if (n == 0) { c = a; return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (wn >= sa) { clear(c); return; } c.xrep.SetLength(sa-wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long i; if (bn == 0) { for (i = 0; i < sa-wn; i++) cp[i] = ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) cp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); cp[sa-wn-1] = ap[sa-1] >> bn; } c.normalize(); } static const _ntl_ulong revtab[256] = { 0UL, 128UL, 64UL, 192UL, 32UL, 160UL, 96UL, 224UL, 16UL, 144UL, 80UL, 208UL, 48UL, 176UL, 112UL, 240UL, 8UL, 136UL, 72UL, 200UL, 40UL, 168UL, 104UL, 232UL, 24UL, 152UL, 88UL, 216UL, 56UL, 184UL, 120UL, 248UL, 4UL, 132UL, 68UL, 196UL, 36UL, 164UL, 100UL, 228UL, 20UL, 148UL, 84UL, 212UL, 52UL, 180UL, 116UL, 244UL, 12UL, 140UL, 76UL, 204UL, 44UL, 172UL, 108UL, 236UL, 28UL, 156UL, 92UL, 220UL, 60UL, 188UL, 124UL, 252UL, 2UL, 130UL, 66UL, 194UL, 34UL, 162UL, 98UL, 226UL, 18UL, 146UL, 82UL, 210UL, 50UL, 178UL, 114UL, 242UL, 10UL, 138UL, 74UL, 202UL, 42UL, 170UL, 106UL, 234UL, 26UL, 154UL, 90UL, 218UL, 58UL, 186UL, 122UL, 250UL, 6UL, 134UL, 70UL, 198UL, 38UL, 166UL, 102UL, 230UL, 22UL, 150UL, 86UL, 214UL, 54UL, 182UL, 118UL, 246UL, 14UL, 142UL, 78UL, 206UL, 46UL, 174UL, 110UL, 238UL, 30UL, 158UL, 94UL, 222UL, 62UL, 190UL, 126UL, 254UL, 1UL, 129UL, 65UL, 193UL, 33UL, 161UL, 97UL, 225UL, 17UL, 145UL, 81UL, 209UL, 49UL, 177UL, 113UL, 241UL, 9UL, 137UL, 73UL, 201UL, 41UL, 169UL, 105UL, 233UL, 25UL, 153UL, 89UL, 217UL, 57UL, 185UL, 121UL, 249UL, 5UL, 133UL, 69UL, 197UL, 37UL, 165UL, 101UL, 229UL, 21UL, 149UL, 85UL, 213UL, 53UL, 181UL, 117UL, 245UL, 13UL, 141UL, 77UL, 205UL, 45UL, 173UL, 109UL, 237UL, 29UL, 157UL, 93UL, 221UL, 61UL, 189UL, 125UL, 253UL, 3UL, 131UL, 67UL, 195UL, 35UL, 163UL, 99UL, 227UL, 19UL, 147UL, 83UL, 211UL, 51UL, 179UL, 115UL, 243UL, 11UL, 139UL, 75UL, 203UL, 43UL, 171UL, 107UL, 235UL, 27UL, 155UL, 91UL, 219UL, 59UL, 187UL, 123UL, 251UL, 7UL, 135UL, 71UL, 199UL, 39UL, 167UL, 103UL, 231UL, 23UL, 151UL, 87UL, 215UL, 55UL, 183UL, 119UL, 247UL, 15UL, 143UL, 79UL, 207UL, 47UL, 175UL, 111UL, 239UL, 31UL, 159UL, 95UL, 223UL, 63UL, 191UL, 127UL, 255UL }; static inline _ntl_ulong rev1(_ntl_ulong a) { return NTL_BB_REV_CODE; } void CopyReverse(GF2X& c, const GF2X& a, long hi) // c[0..hi] = reverse(a[0..hi]), with zero fill as necessary // input may alias output { if (hi < 0) { clear(c); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in CopyReverse"); long n = hi+1; long sa = a.xrep.length(); if (n <= 0 || sa <= 0) { clear(c); return; } long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn != 0) { wn++; bn = NTL_BITS_PER_LONG - bn; } c.xrep.SetLength(wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); long mm = min(sa, wn); long i; for (i = 0; i < mm; i++) cp[i] = ap[i]; for (i = mm; i < wn; i++) cp[i] = 0; if (bn != 0) { for (i = wn-1; i >= 1; i--) cp[i] = (cp[i] << bn) | (cp[i-1] >> (NTL_BITS_PER_LONG-bn)); cp[0] = cp[0] << bn; } for (i = 0; i < wn/2; i++) { _ntl_ulong t; t = cp[i]; cp[i] = cp[wn-1-i]; cp[wn-1-i] = t; } for (i = 0; i < wn; i++) cp[i] = rev1(cp[i]); c.normalize(); } void div(GF2X& q, const GF2X& a, GF2 b) { if (b == 0) ArithmeticError("div: division by zero"); q = a; } void div(GF2X& q, const GF2X& a, long b) { if ((b & 1) == 0) ArithmeticError("div: division by zero"); q = a; } void GF2XFromBytes(GF2X& x, const unsigned char *p, long n) { if (n <= 0) { x = 0; return; } const long BytesPerLong = NTL_BITS_PER_LONG/8; long lw, r, i, j; lw = n/BytesPerLong; r = n - lw*BytesPerLong; if (r != 0) lw++; else r = BytesPerLong; x.xrep.SetLength(lw); unsigned long *xp = x.xrep.elts(); for (i = 0; i < lw-1; i++) { unsigned long t = 0; for (j = 0; j < BytesPerLong; j++) { t >>= 8; t += (((unsigned long)(*p)) & 255UL) << ((BytesPerLong-1)*8); p++; } xp[i] = t; } unsigned long t = 0; for (j = 0; j < r; j++) { t >>= 8; t += (((unsigned long)(*p)) & 255UL) << ((BytesPerLong-1)*8); p++; } t >>= (BytesPerLong-r)*8; xp[lw-1] = t; x.normalize(); } void BytesFromGF2X(unsigned char *p, const GF2X& a, long n) { if (n < 0) n = 0; const long BytesPerLong = NTL_BITS_PER_LONG/8; long lbits = deg(a) + 1; long lbytes = (lbits+7)/8; long min_bytes = min(lbytes, n); long min_words = min_bytes/BytesPerLong; long r = min_bytes - min_words*BytesPerLong; if (r != 0) min_words++; else r = BytesPerLong; const unsigned long *ap = a.xrep.elts(); long i, j; for (i = 0; i < min_words-1; i++) { unsigned long t = ap[i]; for (j = 0; j < BytesPerLong; j++) { *p = t & 255UL; t >>= 8; p++; } } if (min_words > 0) { unsigned long t = ap[min_words-1]; for (j = 0; j < r; j++) { *p = t & 255UL; t >>= 8; p++; } } for (j = min_bytes; j < n; j++) { *p = 0; p++; } } NTL_END_IMPL ntl-11.5.1/src/GF2X1.cpp0000644417616742025610000021343414064716022016246 0ustar gid-shoupvpug-gid-shoupv #include #include #ifndef NTL_WIZARD_HACK #include #endif #if (defined(NTL_WIZARD_HACK) && defined(NTL_GF2X_LIB)) #undef NTL_GF2X_LIB #endif // simple scaling factor for some crossover points: // we use a lower crossover of the underlying multiplication // is faster #if (defined(NTL_GF2X_LIB) || defined(NTL_HAVE_PCLMUL)) #define XOVER_SCALE (1L) #else #define XOVER_SCALE (2L) #endif #define NTL_GF2X_GCD_CROSSOVER (XOVER_SCALE*300L*NTL_BITS_PER_LONG) #define NTL_GF2X_BERMASS_CROSSOVER (XOVER_SCALE*200L*NTL_BITS_PER_LONG) #define NTL_GF2X_HalfGCD_CROSSOVER (4L*NTL_BITS_PER_LONG) NTL_START_IMPL NTL_TLS_GLOBAL_DECL(vec_GF2X, stab) // used by PlainDivRem and PlainRem NTL_TLS_GLOBAL_DECL(WordVector, GF2X_rembuf) void PlainDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { NTL_TLS_GLOBAL_ACCESS(stab); long da, sa, posa, db, sb, posb, dq, sq, posq; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2X: division by zero"); if (da < db) { r = a; clear(q); return; } sa = a.xrep.length(); posa = da - NTL_BITS_PER_LONG*(sa-1); sb = b.xrep.length(); posb = db - NTL_BITS_PER_LONG*(sb-1); dq = da - db; sq = dq/NTL_BITS_PER_LONG + 1; posq = dq - NTL_BITS_PER_LONG*(sq-1); NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } stab.SetLength(NTL_BITS_PER_LONG); long i; NTL_SCOPE(guard) { for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.KillBig(); } }; stab[posb] = b; for (i = 1; i <= min(dq, NTL_BITS_PER_LONG-1); i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG]; long stab_cnt[NTL_BITS_PER_LONG]; for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *qtop = &qp[sq-1]; _ntl_ulong *stab_top; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = stab_ptr[posa]; for (i = stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < db) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } if (posb == 0) sb--; r.xrep.SetLength(sb); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sb; i++) rp[i] = ap[i]; } r.normalize(); guard.relax(); for (i = 0; i <= min(dq, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.KillBig(); } } void PlainDiv(GF2X& q, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(r); PlainDivRem(q, r, a, b); } void PlainRem(GF2X& r, const GF2X& a, const GF2X& b) { NTL_TLS_GLOBAL_ACCESS(stab); long da, sa, posa, db, sb, posb; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("GF2X: division by zero"); if (da < db) { r = a; return; } sa = a.xrep.length(); posa = da - NTL_BITS_PER_LONG*(sa-1); sb = b.xrep.length(); posb = db - NTL_BITS_PER_LONG*(sb-1); NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } stab.SetLength(NTL_BITS_PER_LONG); long i; NTL_SCOPE(guard) { for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.KillBig(); } }; stab[posb] = b; for (i = 1; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); _ntl_ulong *stab_ptr[NTL_BITS_PER_LONG]; long stab_cnt[NTL_BITS_PER_LONG]; for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; while (1) { if (atop[0] & (1UL << posa)) { stab_top = stab_ptr[posa]; for (i = stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < db) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } if (posb == 0) sb--; r.xrep.SetLength(sb); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sb; i++) rp[i] = ap[i]; } r.normalize(); guard.relax(); for (i = 0; i <= min(da-db, NTL_BITS_PER_LONG-1); i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; st.KillBig(); } } #define MASK8 ((1UL << 8)-1UL) static const _ntl_ulong invtab[128] = { 1UL, 255UL, 85UL, 219UL, 73UL, 151UL, 157UL, 51UL, 17UL, 175UL, 69UL, 139UL, 89UL, 199UL, 141UL, 99UL, 33UL, 95UL, 117UL, 123UL, 105UL, 55UL, 189UL, 147UL, 49UL, 15UL, 101UL, 43UL, 121UL, 103UL, 173UL, 195UL, 65UL, 191UL, 21UL, 155UL, 9UL, 215UL, 221UL, 115UL, 81UL, 239UL, 5UL, 203UL, 25UL, 135UL, 205UL, 35UL, 97UL, 31UL, 53UL, 59UL, 41UL, 119UL, 253UL, 211UL, 113UL, 79UL, 37UL, 107UL, 57UL, 39UL, 237UL, 131UL, 129UL, 127UL, 213UL, 91UL, 201UL, 23UL, 29UL, 179UL, 145UL, 47UL, 197UL, 11UL, 217UL, 71UL, 13UL, 227UL, 161UL, 223UL, 245UL, 251UL, 233UL, 183UL, 61UL, 19UL, 177UL, 143UL, 229UL, 171UL, 249UL, 231UL, 45UL, 67UL, 193UL, 63UL, 149UL, 27UL, 137UL, 87UL, 93UL, 243UL, 209UL, 111UL, 133UL, 75UL, 153UL, 7UL, 77UL, 163UL, 225UL, 159UL, 181UL, 187UL, 169UL, 247UL, 125UL, 83UL, 241UL, 207UL, 165UL, 235UL, 185UL, 167UL, 109UL, 3UL }; void NewtonInvTrunc(GF2X& c, const GF2X& a, long e) { if (e == 1) { set(c); return; } NTL_TLS_LOCAL(vec_long, E); E.SetLength(0); append(E, e); while (e > 8) { e = (e+1)/2; append(E, e); } long L = E.length(); NTL_GF2XRegister(g); NTL_GF2XRegister(g0); NTL_GF2XRegister(g1); NTL_GF2XRegister(g2); g.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g0.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g1.xrep.SetMaxLength(((3*E[0]+1)/2+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG+1); g2.xrep.SetMaxLength((E[0]+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG + 1); g.xrep.SetLength(1); g.xrep[0] = invtab[(a.xrep[0] & MASK8) >> 1] & ((1UL< 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); add(g, g, g2); } c = g; } void InvTrunc(GF2X& c, const GF2X& a, long e) { if (ConstTerm(a) == 0 || e < 0) LogicError("inv: bad args"); if (NTL_OVERFLOW(e, 1, 0)) ResourceError("overflow in InvTrunc"); if (e == 0) { clear(c); return; } NewtonInvTrunc(c, a, e); } static long weight1(_ntl_ulong a) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return res; } long weight(const GF2X& a) { long wlen = a.xrep.length(); long res = 0; long i; for (i = 0; i < wlen; i++) res += weight1(a.xrep[i]); return res; } static void SparsityCheck(const GF2X& f, long& k3, long& k2, long& k1) { long w = weight(f); if (w != 3 && w != 5) { k3 = 0; return; } if (ConstTerm(f) != 1) { k3 = 0; return; } GF2X g = f; long n = deg(f); trunc(g, g, n); long t = deg(g); if (n-t < NTL_BITS_PER_LONG || t > (n+1)/2) { k3 = 0; return; } if (w == 3) { k3 = t; k2 = 0; return; } k3 = t; trunc(g, g, t); t = deg(g); k2 = t; trunc(g, g, t); t = deg(g); k1 = t; } const long GF2X_MOD_PLAIN = 0; const long GF2X_MOD_MUL = 1; const long GF2X_MOD_SPECIAL = 2; const long GF2X_MOD_TRI = 3; const long GF2X_MOD_PENT = 4; void build(GF2XModulus& F, const GF2X& f) { long n = deg(f); long i; if (n <= 0) LogicError("build(GF2XModulus,GF2X): deg(f) <= 0"); F.tracevec.make(); F.f = f; F.n = n; F.sn = f.xrep.length(); long sb = F.sn; long posb = n - NTL_BITS_PER_LONG*(sb-1); F.posn = posb; if (F.posn > 0) { F.size = F.sn; F.msk = (1UL << F.posn) - 1UL; } else { F.size = F.sn-1; F.msk = ~0UL; } SparsityCheck(f, F.k3, F.k2, F.k1); if (F.k3 != 0) { if (F.k2 == 0) F.method = GF2X_MOD_TRI; else F.method = GF2X_MOD_PENT; return; } GF2X f0; trunc(f0, f, n); if (F.n >= (NTL_BITS_PER_LONG/2)*XOVER_SCALE) F.method = GF2X_MOD_MUL; else F.method = GF2X_MOD_PLAIN; // NOTE: I've run some tests which indicate that the GF2X_MOD_SPECIAL // method is not worth it. // FIXME: in a future version, I should eliminate all code // and data associated with GF2X_MOD_SPECIAL // NOTE: I've runs some tests which indicate that the crossover // for GF2X_MOD_MUL is extremely low, even without PCLMUL support. if (F.method == GF2X_MOD_SPECIAL) { if (!F.stab_cnt) F.stab_cnt.SetLength(NTL_BITS_PER_LONG); long *stab_cnt = F.stab_cnt.get(); if (!F.stab1) F.stab1.SetLength(2*NTL_BITS_PER_LONG); _ntl_ulong *stab1 = F.stab1.get(); stab1[posb<<1] = f.xrep[0]; stab1[(posb<<1)+1] = 0; stab_cnt[posb] = -sb+1; for (i = 1; i < NTL_BITS_PER_LONG; i++) { long kk0 = ((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG; long kk1 = ((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG; stab1[kk1<<1] = stab1[kk0<<1] << 1; stab1[(kk1<<1)+1] = (stab1[(kk0<<1)+1] << 1) | (stab1[kk0<<1] >> (NTL_BITS_PER_LONG-1)); if (kk1 < posb) stab_cnt[kk1] = -sb; else stab_cnt[kk1] = -sb+1; } } else if (F.method == GF2X_MOD_PLAIN) { vec_GF2X& stab = F.stab; stab.SetLength(NTL_BITS_PER_LONG); if (!F.stab_ptr) F.stab_ptr.SetLength(NTL_BITS_PER_LONG); _ntl_ulong **stab_ptr = F.stab_ptr.get(); if (!F.stab_cnt) F.stab_cnt.SetLength(NTL_BITS_PER_LONG); long *stab_cnt = F.stab_cnt.get(); stab[posb] = f; for (i = 1; i < NTL_BITS_PER_LONG; i++) MulByX(stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG], stab[((_ntl_ulong)(posb+i-1))%NTL_BITS_PER_LONG]); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posb+i))%NTL_BITS_PER_LONG] = -k+1; } } else if (F.method == GF2X_MOD_MUL) { GF2X P1, P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); F.f0 = f0; } } GF2XModulus::GF2XModulus() { n = -1; method = GF2X_MOD_PLAIN; } // The following two routines are total spaghetti...unfortunately, // cleaning them up would require too much re-coding in other // places. GF2XModulus::GF2XModulus(const GF2XModulus& F) : f(F.f), n(F.n), sn(F.sn), posn(F.posn), k3(F.k3), k2(F.k2), k1(F.k1), size(F.size), msk(F.msk), method(F.method), stab(F.stab), h0(F.h0), f0(F.f0), tracevec(F.tracevec) { if (method == GF2X_MOD_SPECIAL) { long i; stab1.SetLength(2*NTL_BITS_PER_LONG); for (i = 0; i < 2*NTL_BITS_PER_LONG; i++) stab1[i] = F.stab1[i]; stab_cnt.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } else if (method == GF2X_MOD_PLAIN) { long i; if (F.stab_cnt) { stab_cnt.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } if (F.stab_ptr) { stab_ptr.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1; } } } } GF2XModulus& GF2XModulus::operator=(const GF2XModulus& F) { if (this == &F) return *this; f=F.f; n=F.n; sn=F.sn; posn=F.posn; k3=F.k3; k2=F.k2; k1=F.k1; size=F.size; msk=F.msk; method=F.method; stab=F.stab; h0=F.h0; f0 = F.f0; tracevec=F.tracevec; if (method == GF2X_MOD_SPECIAL) { long i; if (!stab1) stab1.SetLength(2*NTL_BITS_PER_LONG); for (i = 0; i < 2*NTL_BITS_PER_LONG; i++) stab1[i] = F.stab1[i]; if (!stab_cnt) stab_cnt.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } else if (method == GF2X_MOD_PLAIN) { long i; if (F.stab_cnt) { if (!stab_cnt) stab_cnt.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) stab_cnt[i] = F.stab_cnt[i]; } if (F.stab_ptr) { if (!stab_ptr) stab_ptr.SetLength(NTL_BITS_PER_LONG); for (i = 0; i < NTL_BITS_PER_LONG; i++) { WordVector& st = stab[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG].xrep; long k = st.length(); stab_ptr[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = &st[k-1]; stab_cnt[((_ntl_ulong)(posn+i))%NTL_BITS_PER_LONG] = -k+1; } } } return *this; } GF2XModulus::GF2XModulus(const GF2X& ff) { n = -1; method = GF2X_MOD_PLAIN; build(*this, ff); } void UseMulRem21(GF2X& r, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); } void UseMulDivRem21(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); add(r, r, P1); q = P2; } void UseMulDiv21(GF2X& q, const GF2X& a, const GF2XModulus& F) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); add(P2, P2, P1); q = P2; } void UseMulRemX1(GF2X& r, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); clear(buf); a = aa; long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulRem21(buf, buf, F); a_len -= amt; } r = buf; } void UseMulDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulDivRem21(qbuf, buf, buf, F); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } void UseMulDivX1(GF2X& q, const GF2X& aa, const GF2XModulus& F) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long n = F.n; long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); UseMulDivRem21(qbuf, buf, buf, F); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } static void TrinomReduce(GF2X& x, const GF2X& a, long n, long k) { long wn = n / NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long wdiff = (n-k)/NTL_BITS_PER_LONG; long bdiff = (n-k) - wdiff*NTL_BITS_PER_LONG; long m = a.xrep.length()-1; if (wn > m) { x = a; return; } NTL_GF2XRegister(r); r = a; _ntl_ulong *p = r.xrep.elts(); _ntl_ulong *pp; _ntl_ulong w; if (bn == 0) { if (bdiff == 0) { // bn == 0 && bdiff == 0 while (m >= wn) { w = p[m]; p[m-wdiff] ^= w; p[m-wn] ^= w; m--; } } else { // bn == 0 && bdiff != 0 while (m >= wn) { w = p[m]; pp = &p[m-wdiff]; *pp ^= (w >> bdiff); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff)); p[m-wn] ^= w; m--; } } } else { if (bdiff == 0) { // bn != 0 && bdiff == 0 while (m > wn) { w = p[m]; p[m-wdiff] ^= w; pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); m--; } w = (p[m] >> bn) << bn;; p[m-wdiff] ^= w; p[0] ^= (w >> bn); p[m] &= ((1UL< wn) { w = p[m]; pp = &p[m-wdiff]; *pp ^= (w >> bdiff);; *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff)); pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); m--; } w = (p[m] >> bn) << bn;; p[m-wdiff] ^= (w >> bdiff); if (m-wdiff-1 >= 0) p[m-wdiff-1] ^= (w << (NTL_BITS_PER_LONG-bdiff)); p[0] ^= (w >> bn); p[m] &= ((1UL<= 0 && p[wn] == 0) wn--; r.xrep.QuickSetLength(wn+1); x = r; } static void PentReduce(GF2X& x, const GF2X& a, long n, long k3, long k2, long k1) { long wn = n / NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long m = a.xrep.length()-1; if (wn > m) { x = a; return; } long wdiff1 = (n-k1)/NTL_BITS_PER_LONG; long bdiff1 = (n-k1) - wdiff1*NTL_BITS_PER_LONG; long wdiff2 = (n-k2)/NTL_BITS_PER_LONG; long bdiff2 = (n-k2) - wdiff2*NTL_BITS_PER_LONG; long wdiff3 = (n-k3)/NTL_BITS_PER_LONG; long bdiff3 = (n-k3) - wdiff3*NTL_BITS_PER_LONG; NTL_GF2XRegister(r); r = a; _ntl_ulong *p = r.xrep.elts(); _ntl_ulong *pp; _ntl_ulong w; while (m > wn) { w = p[m]; if (bn == 0) p[m-wn] ^= w; else { pp = &p[m-wn]; *pp ^= (w >> bn); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bn)); } if (bdiff1 == 0) p[m-wdiff1] ^= w; else { pp = &p[m-wdiff1]; *pp ^= (w >> bdiff1); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff1)); } if (bdiff2 == 0) p[m-wdiff2] ^= w; else { pp = &p[m-wdiff2]; *pp ^= (w >> bdiff2); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff2)); } if (bdiff3 == 0) p[m-wdiff3] ^= w; else { pp = &p[m-wdiff3]; *pp ^= (w >> bdiff3); *(pp-1) ^= (w << (NTL_BITS_PER_LONG-bdiff3)); } m--; } w = (p[m] >> bn) << bn; p[0] ^= (w >> bn); if (bdiff1 == 0) p[m-wdiff1] ^= w; else { p[m-wdiff1] ^= (w >> bdiff1); if (m-wdiff1-1 >= 0) p[m-wdiff1-1] ^= (w << (NTL_BITS_PER_LONG-bdiff1)); } if (bdiff2 == 0) p[m-wdiff2] ^= w; else { p[m-wdiff2] ^= (w >> bdiff2); if (m-wdiff2-1 >= 0) p[m-wdiff2-1] ^= (w << (NTL_BITS_PER_LONG-bdiff2)); } if (bdiff3 == 0) p[m-wdiff3] ^= w; else { p[m-wdiff3] ^= (w >> bdiff3); if (m-wdiff3-1 >= 0) p[m-wdiff3-1] ^= (w << (NTL_BITS_PER_LONG-bdiff3)); } if (bn != 0) p[m] &= ((1UL<= 0 && p[wn] == 0) wn--; r.xrep.QuickSetLength(wn+1); x = r; } static void RightShiftAdd(GF2X& c, const GF2X& a, long n) { if (n < 0) { LogicError("RightShiftAdd: negative shamt"); } if (n == 0) { add(c, c, a); return; } long sa = a.xrep.length(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (wn >= sa) { return; } long sc = c.xrep.length(); long i; if (sa-wn > sc) c.xrep.SetLength(sa-wn); _ntl_ulong *cp = c.xrep.elts(); const _ntl_ulong *ap = a.xrep.elts(); for (i = sc; i < sa-wn; i++) cp[i] = 0; if (bn == 0) { for (i = 0; i < sa-wn; i++) cp[i] ^= ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) cp[i] ^= (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); cp[sa-wn-1] ^= ap[sa-1] >> bn; } c.normalize(); } static void TriDiv21(GF2X& q, const GF2X& a, long n, long k) { NTL_GF2XRegister(P1); RightShift(P1, a, n); if (k != 1) RightShiftAdd(P1, P1, n-k); q = P1; } static void TriDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n, long k) { NTL_GF2XRegister(Q); TriDiv21(Q, a, n, k); TrinomReduce(r, a, n, k); q = Q; } static void PentDiv21(GF2X& q, const GF2X& a, long n, long k3, long k2, long k1) { if (deg(a) < n) { clear(q); return; } NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); RightShift(P1, a, n); RightShift(P2, P1, n-k3); RightShiftAdd(P2, P1, n-k2); if (k1 != 1) { RightShiftAdd(P2, P1, n-k1); } add(P2, P2, P1); q = P2; } static void PentDivRem21(GF2X& q, GF2X& r, const GF2X& a, long n, long k3, long k2, long k1) { NTL_GF2XRegister(Q); PentDiv21(Q, a, n, k3, k2, k1); PentReduce(r, a, n, k3, k2, k1); q = Q; } static void TriDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n, long k) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); TriDivRem21(qbuf, buf, buf, n, k); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } static void TriDivX1(GF2X& q, const GF2X& aa, long n, long k) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); TriDivRem21(qbuf, buf, buf, n, k); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } static void PentDivRemX1(GF2X& q, GF2X& r, const GF2X& aa, long n, long k3, long k2, long k1) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); PentDivRem21(qbuf, buf, buf, n, k3, k2, k1); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } r = buf; q = qq; } static void PentDivX1(GF2X& q, const GF2X& aa, long n, long k3, long k2, long k1) { NTL_GF2XRegister(buf); NTL_GF2XRegister(tmp); NTL_GF2XRegister(a); NTL_GF2XRegister(qq); NTL_GF2XRegister(qbuf); clear(buf); a = aa; clear(qq); long a_len = deg(a) + 1; while (a_len > 0) { long old_buf_len = deg(buf) + 1; long amt = min(2*n-1-old_buf_len, a_len); LeftShift(buf, buf, amt); RightShift(tmp, a, a_len-amt); add(buf, buf, tmp); trunc(a, a, a_len-amt); PentDivRem21(qbuf, buf, buf, n, k3, k2, k1); a_len -= amt; ShiftAdd(qq, qbuf, a_len); } q = qq; } void rem(GF2X& r, const GF2X& a, const GF2XModulus& F) { long n = F.n; if (n < 0) LogicError("rem: uninitialized modulus"); if (F.method == GF2X_MOD_TRI) { TrinomReduce(r, a, n, F.k3); return; } if (F.method == GF2X_MOD_PENT) { PentReduce(r, a, n, F.k3, F.k2, F.k1); return; } long da = deg(a); if (da < n) { r = a; } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulRem21(r, a, F); else UseMulRemX1(r, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; while (1) { if (atop[0] & (1UL << posa)) { stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.xrep[sn-1] &= F.msk; r.normalize(); } else { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; while (1) { if (atop[0] & (1UL << posa)) { stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.normalize(); } } void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("DivRem: uninitialized modulus"); if (da < n) { r = a; clear(q); } else if (F.method == GF2X_MOD_TRI) { if (da <= 2*(n-1)) TriDivRem21(q, r, a, F.n, F.k3); else TriDivRemX1(q, r, a, F.n, F.k3); } else if (F.method == GF2X_MOD_PENT) { if (da <= 2*(n-1)) PentDivRem21(q, r, a, F.n, F.k3, F.k2, F.k1); else PentDivRemX1(q, r, a, F.n, F.k3, F.k2, F.k1); } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulDivRem21(q, r, a, F); else UseMulDivRemX1(q, r, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.xrep[sn-1] &= F.msk; r.normalize(); } else { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; if (&r == &a) ap = r.xrep.elts(); else { GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); } _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } long sn = F.size; r.xrep.SetLength(sn); if (&r != &a) { _ntl_ulong *rp = r.xrep.elts(); for (i = 0; i < sn; i++) rp[i] = ap[i]; } r.normalize(); } } void div(GF2X& q, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("div: uninitialized modulus"); if (da < n) { clear(q); } else if (F.method == GF2X_MOD_TRI) { if (da <= 2*(n-1)) TriDiv21(q, a, F.n, F.k3); else TriDivX1(q, a, F.n, F.k3); } else if (F.method == GF2X_MOD_PENT) { if (da <= 2*(n-1)) PentDiv21(q, a, F.n, F.k3, F.k2, F.k1); else PentDivX1(q, a, F.n, F.k3, F.k2, F.k1); } else if (F.method == GF2X_MOD_MUL) { if (da <= 2*(n-1)) UseMulDiv21(q, a, F); else UseMulDivX1(q, a, F); } else if (F.method == GF2X_MOD_SPECIAL) { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = &F.stab1[posa << 1]; i = F.stab_cnt[posa]; atop[i] ^= stab_top[0]; atop[i+1] ^= stab_top[1]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } } else { NTL_TLS_GLOBAL_ACCESS(GF2X_rembuf); WordVectorWatcher watch_GF2X_rembuf(GF2X_rembuf); long sa = a.xrep.length(); long posa = da - NTL_BITS_PER_LONG*(sa-1); long dq = da - n; long sq = dq/NTL_BITS_PER_LONG + 1; long posq = dq - NTL_BITS_PER_LONG*(sq-1); _ntl_ulong *ap; GF2X_rembuf = a.xrep; ap = GF2X_rembuf.elts(); _ntl_ulong *atop = &ap[sa-1]; _ntl_ulong *stab_top; long i; q.xrep.SetLength(sq); _ntl_ulong *qp = q.xrep.elts(); for (i = 0; i < sq; i++) qp[i] = 0; _ntl_ulong *qtop = &qp[sq-1]; while (1) { if (atop[0] & (1UL << posa)) { qtop[0] |= (1UL << posq); stab_top = F.stab_ptr[posa]; for (i = F.stab_cnt[posa]; i <= 0; i++) atop[i] ^= stab_top[i]; } da--; if (da < n) break; posa--; if (posa < 0) { posa = NTL_BITS_PER_LONG-1; atop--; } posq--; if (posq < 0) { posq = NTL_BITS_PER_LONG-1; qtop--; } } } } void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2XModulus& F) { if (F.n < 0) LogicError("MulMod: uninitialized modulus"); NTL_GF2XRegister(t); mul(t, a, b); rem(c, t, F); } void SqrMod(GF2X& c, const GF2X& a, const GF2XModulus& F) { if (F.n < 0) LogicError("SqrMod: uninitialized modulus"); NTL_GF2XRegister(t); sqr(t, a); rem(c, t, F); } // we need these two versions to prevent a GF2XModulus // from being constructed. void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2X& f) { NTL_GF2XRegister(t); mul(t, a, b); rem(c, t, f); } void SqrMod(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(t); sqr(t, a); rem(c, t, f); } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(GF2X& h, const GF2X& g, const ZZ& e, const GF2XModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); GF2X res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 9); vec_GF2X v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { GF2X t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void PowerXMod(GF2X& hh, const ZZ& e, const GF2XModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; GF2X h; h.SetMaxLength(F.n+1); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByX(h, h); if (coeff(h, F.n) != 0) add(h, h, F.f); } } if (e < 0) InvMod(h, h, F); hh = h; } void UseMulRem(GF2X& r, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; } void UseMulDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); add(P1, P1, a); r = P1; q = P2; } void UseMulDiv(GF2X& q, const GF2X& a, const GF2X& b) { NTL_GF2XRegister(P1); NTL_GF2XRegister(P2); long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } const long GF2X_DIV_CROSS = (NTL_BITS_PER_LONG/2)*XOVER_SCALE; void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b) { long da = deg(a); long db = deg(b); if (db < GF2X_DIV_CROSS || da-db < GF2X_DIV_CROSS) PlainDivRem(q, r, a, b); else if (da < 4*db) UseMulDivRem(q, r, a, b); else { GF2XModulus B; build(B, b); DivRem(q, r, a, B); } } void div(GF2X& q, const GF2X& a, const GF2X& b) { long da = deg(a); long db = deg(b); if (db < GF2X_DIV_CROSS || da-db < GF2X_DIV_CROSS) PlainDiv(q, a, b); else if (da < 4*db) UseMulDiv(q, a, b); else { GF2XModulus B; build(B, b); div(q, a, B); } } void rem(GF2X& r, const GF2X& a, const GF2X& b) { long da = deg(a); long db = deg(b); if (db < GF2X_DIV_CROSS || da-db < GF2X_DIV_CROSS) PlainRem(r, a, b); else if (da < 4*db) UseMulRem(r, a, b); else { GF2XModulus B; build(B, b); rem(r, a, B); } } static inline void swap(_ntl_ulong_ptr& a, _ntl_ulong_ptr& b) { _ntl_ulong_ptr t; t = a; a = b; b = t; } static void BaseGCD(GF2X& d, const GF2X& a_in, const GF2X& b_in) { NTL_GF2XRegister(a); NTL_GF2XRegister(b); if (IsZero(a_in)) { d = b_in; return; } if (IsZero(b_in)) { d = a_in; return; } a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da < db) { swap(ap, bp); swap(da, db); swap(wa, wb); swap(ba, bb); parity = 1 - parity; } // da >= db if (db == -1) break; ShiftAdd(ap, bp, wb+1, da-db); _ntl_ulong msk = 1UL << ba; _ntl_ulong aa = ap[wa]; while ((aa & msk) == 0) { da--; msk = msk >> 1; ba--; if (!msk) { wa--; ba = NTL_BITS_PER_LONG-1; msk = 1UL << (NTL_BITS_PER_LONG-1); if (wa < 0) break; aa = ap[wa]; } } } a.normalize(); b.normalize(); if (!parity) { d = a; } else { d = b; } } void OldGCD(GF2X& d, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb >= 10 && 2*sa > 3*sb) { NTL_GF2XRegister(r); rem(r, a, b); BaseGCD(d, b, r); } else if (sa >= 10 && 2*sb > 3*sa) { NTL_GF2XRegister(r); rem(r, b, a); BaseGCD(d, a, r); } else { BaseGCD(d, a, b); } } #define XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss) \ long delta = da-db; \ \ if (delta == 0) { \ long i; \ for (i = wb; i >= 0; i--) ap[i] ^= bp[i]; \ for (i = ss-1; i >= 0; i--) rp[i] ^= sp[i]; \ if (ss > sr) sr = ss; \ } \ else if (delta == 1) { \ long i; \ _ntl_ulong tt, tt1; \ \ tt = bp[wb] >> (NTL_BITS_PER_LONG-1); \ if (tt) ap[wb+1] ^= tt; \ tt = bp[wb]; \ for (i = wb; i >= 1; i--) \ tt1 = bp[i-1], ap[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)), \ tt = tt1; \ ap[0] ^= tt << 1; \ \ if (ss > 0) { \ long t = ss; \ tt = sp[ss-1] >> (NTL_BITS_PER_LONG-1); \ if (tt) rp[ss] ^= tt, t++; \ tt = sp[ss-1]; \ for (i = ss-1; i >= 1; i--) \ tt1=sp[i-1], \ rp[i] ^= (tt << 1) | (tt1 >> (NTL_BITS_PER_LONG-1)), \ tt = tt1; \ rp[0] ^= tt << 1; \ if (t > sr) sr = t; \ } \ } \ else if (delta < NTL_BITS_PER_LONG) { \ long i; \ _ntl_ulong tt, tt1; \ long rdelta = NTL_BITS_PER_LONG-delta; \ \ tt = bp[wb] >> rdelta; \ if (tt) ap[wb+1] ^= tt; \ tt=bp[wb]; \ for (i = wb; i >= 1; i--) \ tt1=bp[i-1], ap[i] ^= (tt << delta) | (tt1 >> rdelta), \ tt=tt1; \ ap[0] ^= tt << delta; \ \ if (ss > 0) { \ long t = ss; \ tt = sp[ss-1] >> rdelta; \ if (tt) rp[ss] ^= tt, t++; \ tt=sp[ss-1]; \ for (i = ss-1; i >= 1; i--) \ tt1=sp[i-1], rp[i] ^= (tt << delta) | (tt1 >> rdelta), \ tt=tt1; \ rp[0] ^= tt << delta; \ if (t > sr) sr = t; \ } \ } \ else { \ ShiftAdd(ap, bp, wb+1, da-db); \ ShiftAdd(rp, sp, ss, da-db); \ long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; \ if (t > sr) { \ while (t > 0 && rp[t-1] == 0) t--; \ sr = t; \ } \ } \ \ _ntl_ulong msk = 1UL << ba; \ _ntl_ulong aa = ap[wa]; \ \ while ((aa & msk) == 0) { \ da--; \ msk = msk >> 1; \ ba--; \ if (!msk) { \ wa--; \ ba = NTL_BITS_PER_LONG-1; \ msk = 1UL << (NTL_BITS_PER_LONG-1); \ if (wa < 0) break; \ aa = ap[wa]; \ } \ } \ static void XXGCD(GF2X& d, GF2X& r_out, const GF2X& a_in, const GF2X& b_in) { NTL_GF2XRegister(a); NTL_GF2XRegister(b); NTL_GF2XRegister(r); NTL_GF2XRegister(s); if (IsZero(b_in)) { d = a_in; set(r_out); return; } if (IsZero(a_in)) { d = b_in; clear(r_out); return; } a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); long max_sz = max(a_in.xrep.length(), b_in.xrep.length()); r.xrep.SetLength(max_sz+1); s.xrep.SetLength(max_sz+1); _ntl_ulong *rp = r.xrep.elts(); _ntl_ulong *sp = s.xrep.elts(); long i; for (i = 0; i <= max_sz; i++) { rp[i] = sp[i] = 0; } rp[0] = 1; long sr = 1; long ss = 0; a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da == -1 || db == -1) break; if (da < db || (da == db && parity)) { if (da < db && !parity) parity = 1; XX_STEP(bp,db,wb,bb,sp,ss,ap,da,wa,ba,rp,sr) } else { parity = 0; XX_STEP(ap,da,wa,ba,rp,sr,bp,db,wb,bb,sp,ss) } } a.normalize(); b.normalize(); r.normalize(); s.normalize(); if (db == -1) { d = a; r_out = r; } else { d = b; r_out = s; } } static void BaseXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { if (IsZero(b)) { d = a; set(s); clear(t); } else { NTL_GF2XRegister(t1); NTL_GF2XRegister(b1); b1 = b; XXGCD(d, s, a, b); mul(t1, a, s); add(t1, t1, d); div(t, t1, b1); } } void OldXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { long sa = a.xrep.length(); long sb = b.xrep.length(); if (sb >= 10 && 2*sa > 3*sb) { NTL_GF2XRegister(r); NTL_GF2XRegister(q); NTL_GF2XRegister(s1); NTL_GF2XRegister(t1); DivRem(q, r, a, b); BaseXGCD(d, s1, t1, b, r); mul(r, t1, q); add(r, r, s1); // r = s1 - t1*q, but sign doesn't matter s = t1; t = r; } else if (sa >= 10 && 2*sb > 3*sa) { NTL_GF2XRegister(r); NTL_GF2XRegister(q); NTL_GF2XRegister(s1); NTL_GF2XRegister(t1); DivRem(q, r, b, a); BaseXGCD(d, s1, t1, a, r); mul(r, t1, q); add(r, r, s1); // r = s1 - t1*q, but sign doesn't matter t = t1; s = r; } else { BaseXGCD(d, s, t, a, b); } } static void BaseInvMod(GF2X& d, GF2X& s, const GF2X& a, const GF2X& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); long sa = a.xrep.length(); long sf = f.xrep.length(); if ((sa >= 10 && 2*sf > 3*sa) || sf > NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { NTL_GF2XRegister(t); XGCD(d, s, t, a, f); } else { XXGCD(d, s, a, f); } } void InvMod(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(d); NTL_GF2XRegister(s); BaseInvMod(d, s, a, f); if (!IsOne(d)) InvModError("InvMod: inverse undefined"); c = s; } long InvModStatus(GF2X& c, const GF2X& a, const GF2X& f) { NTL_GF2XRegister(d); NTL_GF2XRegister(s); BaseInvMod(d, s, a, f); if (!IsOne(d)) { c = d; return 1; } c = s; return 0; } void diff(GF2X& c, const GF2X& a) { RightShift(c, a, 1); // clear odd coeffs long dc = deg(c); long i; for (i = 1; i <= dc; i += 2) SetCoeff(c, i, 0); } void conv(GF2X& c, long a) { if (a & 1) set(c); else clear(c); } void conv(GF2X& c, GF2 a) { if (a == 1) set(c); else clear(c); } void conv(GF2X& x, const vec_GF2& a) { x.xrep = a.rep; x.normalize(); } void conv(vec_GF2& x, const GF2X& a) { VectorCopy(x, a, deg(a)+1); } /* additional legacy conversions for v6 conversion regime */ #ifndef NTL_WIZARD_HACK void conv(GF2X& x, const ZZX& a) { long n = deg(a) + 1; long i; x.SetLength(n); for (i = 0; i < n; i++) conv(x[i], a[i]); x.normalize(); } void conv(ZZX& x, const GF2X& a) { long n = deg(a) + 1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) x.rep[i] = rep(coeff(a, i)); x.normalize(); } #endif /* ------------------------------------- */ void VectorCopy(vec_GF2& x, const GF2X& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long wa = a.xrep.length(); long wx = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long wmin = min(wa, wx); x.SetLength(n); const _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *xp = x.rep.elts(); long i; for (i = 0; i < wmin; i++) xp[i] = ap[i]; if (wa < wx) { for (i = wa; i < wx; i++) xp[i] = 0; } else { long p = n % NTL_BITS_PER_LONG; if (p != 0) xp[wx-1] &= (1UL << p) - 1UL; } } void add(GF2X& c, const GF2X& a, long b) { c = a; if (b & 1) { long n = c.xrep.length(); if (n == 0) set(c); else { c.xrep[0] ^= 1; if (n == 1 && !c.xrep[0]) c.xrep.SetLength(0); } } } void add(GF2X& c, const GF2X& a, GF2 b) { add(c, a, rep(b)); } void MulTrunc(GF2X& c, const GF2X& a, const GF2X& b, long n) { NTL_GF2XRegister(t); mul(t, a, b); trunc(c, t, n); } void SqrTrunc(GF2X& c, const GF2X& a, long n) { NTL_GF2XRegister(t); sqr(t, a); trunc(c, t, n); } long divide(GF2X& q, const GF2X& a, const GF2X& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } NTL_GF2XRegister(lq); NTL_GF2XRegister(r); DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const GF2X& a, const GF2X& b) { if (IsZero(b)) return IsZero(a); NTL_GF2XRegister(r); rem(r, a, b); if (!IsZero(r)) return 0; return 1; } /*** modular composition routines and data structures ***/ void InnerProduct(GF2X& x, const GF2X& v, long dv, long low, long high, const vec_GF2X& H, long n, WordVector& t) { long i, j; _ntl_ulong *tp = t.elts(); for (i = 0; i < n; i++) tp[i] = 0; long w_low = low/NTL_BITS_PER_LONG; long b_low = low - w_low*NTL_BITS_PER_LONG; const _ntl_ulong *vp = &v.xrep[w_low]; _ntl_ulong msk = 1UL << b_low; _ntl_ulong vv = *vp; high = min(high, dv); i = low; for (;;) { if (vv & msk) { const WordVector& h = H[i-low].xrep; long m = h.length(); const _ntl_ulong *hp = h.elts(); for (j = 0; j < m; j++) tp[j] ^= hp[j]; } i++; if (i > high) break; msk = msk << 1; if (!msk) { msk = 1UL; vp++; vv = *vp; } } x.xrep = t; x.normalize(); } void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& A, const GF2XModulus& F) { long dg = deg(g); if (dg <= 0) { x = g; return; } GF2X s, t; WordVector scratch(INIT_SIZE, F.size); long m = A.H.length() - 1; long l = (((dg+1)+m-1)/m) - 1; InnerProduct(t, g, dg, l*m, l*m + m - 1, A.H, F.size, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g, dg, i*m, i*m + m - 1, A.H, F.size, scratch); MulMod(t, t, A.H[m], F); add(t, t, s); } x = t; } void build(GF2XArgument& A, const GF2X& h, const GF2XModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) LogicError("build GF2XArgument: bad args"); if (m > F.n) m = F.n; long i; A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F) // x = g(h) mod f { long m = SqrRoot(deg(g)+1); if (m == 0) { clear(x); return; } GF2XArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F) { long m = SqrRoot(deg(g1) + deg(g2) + 2); if (m == 0) { clear(x1); clear(x2); return; } GF2XArgument A; build(A, h, F, m); GF2X xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F) { long m = SqrRoot(deg(g1) + deg(g2) + deg(g3) + 3); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } GF2XArgument A; build(A, h, F, m); GF2X xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); GF2X t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); if (F.method != GF2X_MOD_TRI && F.method != GF2X_MOD_PENT) { // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); } if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(GF2X& x, const GF2X& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); NTL_GF2XRegister(t1); NTL_GF2XRegister(t2); NTL_GF2XRegister(t3); mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); if (F.method == GF2X_MOD_TRI) { RightShift(t2, a, F.k3); add(t2, t2, a); } else if (F.method == GF2X_MOD_PENT) { RightShift(t2, a, F.k3); RightShift(t3, a, F.k2); add(t2, t2, t3); RightShift(t3, a, F.k1); add(t2, t2, t3); add(t2, t2, a); } else { mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); } trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); MulByX(t2, t2); add(x, t1, t2); } void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { NTL_GF2XRegister(xx); NTL_GF2XRegister(aa); conv(aa, a); TransMulMod(xx, aa, B, F); conv(x, xx); } void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2XArgument& H, const GF2XModulus& F) { long n = F.n; if (deg(a) >= n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive parameter"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; GF2XTransMultiplier M; build(M, H.H[m], F); GF2X s; s = a; x.SetMaxLength(k); clear(x); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) SetCoeff(x, i*m+j, InnerProduct(H.H[j].xrep, s.xrep)); if (i < l) TransMulMod(s, s, M, F); } } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F) { GF2X xx; ProjectPowers(xx, to_GF2X(a), k, H, F); VectorCopy(x, xx, k); } void ProjectPowers(GF2X& x, const GF2X& a, long k, const GF2X& h, const GF2XModulus& F) { if (deg(a) >= F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { clear(x); return; } long m = SqrRoot(k); GF2XArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& H, const GF2XModulus& F) { GF2X xx; ProjectPowers(xx, to_GF2X(a), k, H, F); VectorCopy(x, xx, k); } void OldMinPolyInternal(GF2X& h, const GF2X& x, long m) { GF2X a, b, r, s; GF2X a_in, b_in; if (IsZero(x)) { set(h); return; } clear(a_in); SetCoeff(a_in, 2*m); CopyReverse(b_in, x, 2*m-1); a.xrep.SetMaxLength(a_in.xrep.length()+1); b.xrep.SetMaxLength(b_in.xrep.length()+1); long max_sz = max(a_in.xrep.length(), b_in.xrep.length()); r.xrep.SetLength(max_sz+1); s.xrep.SetLength(max_sz+1); _ntl_ulong *rp = r.xrep.elts(); _ntl_ulong *sp = s.xrep.elts(); long i; for (i = 0; i <= max_sz; i++) { rp[i] = sp[i] = 0; } sp[0] = 1; long sr = 0; long ss = 1; a = a_in; b = b_in; _ntl_ulong *ap = a.xrep.elts(); _ntl_ulong *bp = b.xrep.elts(); long da = deg(a); long wa = da/NTL_BITS_PER_LONG; long ba = da - wa*NTL_BITS_PER_LONG; long db = deg(b); long wb = db/NTL_BITS_PER_LONG; long bb = db - wb*NTL_BITS_PER_LONG; long parity = 0; for (;;) { if (da < db) { swap(ap, bp); swap(da, db); swap(wa, wb); swap(ba, bb); parity = 1 - parity; swap(rp, sp); swap(sr, ss); } // da >= db if (db < m) break; ShiftAdd(ap, bp, wb+1, da-db); ShiftAdd(rp, sp, ss, da-db); long t = ss + (da-db+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; if (t > sr) { while (t > 0 && rp[t-1] == 0) t--; sr = t; } _ntl_ulong msk = 1UL << ba; _ntl_ulong aa = ap[wa]; while ((aa & msk) == 0) { da--; msk = msk >> 1; ba--; if (!msk) { wa--; ba = NTL_BITS_PER_LONG-1; msk = 1UL << (NTL_BITS_PER_LONG-1); if (wa < 0) break; aa = ap[wa]; } } } a.normalize(); b.normalize(); r.normalize(); s.normalize(); if (!parity) { h = s; } else { h = r; } } void DoMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m, const GF2X& R) { GF2X x; ProjectPowers(x, R, 2*m, g, F); MinPolyInternal(h, x, m); } void MinPolySeq(GF2X& h, const vec_GF2& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); GF2X x; x.xrep = a.rep; x.normalize(); MinPolyInternal(h, x, m); } void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); GF2X R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m) { GF2X h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ GF2X h2, h3; GF2X R; GF2XTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m) { if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); GF2X R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F) { MinPolyMod(hh, g, F, F.n); } void MulByXMod(GF2X& c, const GF2X& a, const GF2XModulus& F) { long da = deg(a); long df = deg(F); if (da >= df) LogicError("MulByXMod: bad args"); MulByX(c, a); if (da >= 0 && da == df-1) add(c, c, F); } static void MulByXModAux(GF2X& c, const GF2X& a, const GF2X& f) { long da = deg(a); long df = deg(f); if (da >= df) LogicError("MulByXMod: bad args"); MulByX(c, a); if (da >= 0 && da == df-1) add(c, c, f); } void MulByXMod(GF2X& h, const GF2X& a, const GF2X& f) { if (&h == &f) { GF2X hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void power(GF2X& x, const GF2X& a, long e) { if (e < 0) { ArithmeticError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); GF2X res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_GF2& S, const GF2XModulus& f) { long n = deg(f); if (n <= 0) LogicError("TraceVec: bad args"); GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); VectorCopy(S, x, n); S.put(0, to_GF2(n)); } static void PlainTraceVec(vec_GF2& S, const GF2X& f) { long n = deg(f); if (n <= 0) LogicError("TraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } GF2X x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); VectorCopy(S, x, n); S.put(0, to_GF2(n)); } void TraceVec(vec_GF2& S, const GF2X& f) { PlainTraceVec(S, f); } static void ComputeTraceVec(vec_GF2& S, const GF2XModulus& F) { if (F.method == GF2X_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(ref_GF2 x, const GF2X& a, const GF2XModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); project(x, *F.tracevec.val(), a); } void TraceMod(ref_GF2 x, const GF2X& a, const GF2X& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } // New versions of GCD, XGCD, and MinPolyInternal // and support routines class _NTL_GF2XMatrix { private: _NTL_GF2XMatrix(const _NTL_GF2XMatrix&); // disable GF2X elts[2][2]; public: _NTL_GF2XMatrix() { } ~_NTL_GF2XMatrix() { } void operator=(const _NTL_GF2XMatrix&); GF2X& operator() (long i, long j) { return elts[i][j]; } const GF2X& operator() (long i, long j) const { return elts[i][j]; } }; void _NTL_GF2XMatrix::operator=(const _NTL_GF2XMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } static void mul(GF2X& U, GF2X& V, const _NTL_GF2XMatrix& M) // (U, V)^T = M*(U, V)^T { GF2X t1, t2, t3; mul(t1, M(0,0), U); mul(t2, M(0,1), V); add(t3, t1, t2); mul(t1, M(1,0), U); mul(t2, M(1,1), V); add(V, t1, t2); U = t3; } static void mul(_NTL_GF2XMatrix& A, _NTL_GF2XMatrix& B, _NTL_GF2XMatrix& C) // A = B*C, B and C are destroyed { GF2X t1, t2; mul(t1, B(0,0), C(0,0)); mul(t2, B(0,1), C(1,0)); add(A(0,0), t1, t2); mul(t1, B(1,0), C(0,0)); mul(t2, B(1,1), C(1,0)); add(A(1,0), t1, t2); mul(t1, B(0,0), C(0,1)); mul(t2, B(0,1), C(1,1)); add(A(0,1), t1, t2); mul(t1, B(1,0), C(0,1)); mul(t2, B(1,1), C(1,1)); add(A(1,1), t1, t2); long i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { B(i,j).kill(); C(i,j).kill(); } } } static void IterHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; GF2X Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { DivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } static void HalfGCD(_NTL_GF2XMatrix& M_out, const GF2X& U, const GF2X& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; GF2X U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } GF2X Q; _NTL_GF2XMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } static void HalfGCD(GF2X& U, GF2X& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); GF2X Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(GF2X& d, const GF2X& u, const GF2X& v) { long su = u.xrep.length(); long sv = v.xrep.length(); if (su <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG && sv <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { OldGCD(d, u, v); return; } GF2X u1, v1; u1 = u; v1 = v; long du1 = deg(u1); long dv1 = deg(v1); if (du1 == dv1) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (du1 < dv1) { swap(u1, v1); du1 = dv1; } // deg(u1) > deg(v1) while (du1 >= NTL_GF2X_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } du1 = deg(u1); } OldGCD(d, u1, v1); } static void XHalfGCD(_NTL_GF2XMatrix& M_out, GF2X& U, GF2X& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_GF2X_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_GF2XMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } GF2X Q; _NTL_GF2XMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); GF2X t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b) { // GF2 w; long sa = a.xrep.length(); long sb = b.xrep.length(); if (sa <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG && sb <= NTL_GF2X_GCD_CROSSOVER/NTL_BITS_PER_LONG) { OldXGCD(d, s, t, a, b); return; } GF2X U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } _NTL_GF2XMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize // inv(w, LeadCoeff(d)); // mul(d, d, w); // mul(s, s, w); // mul(t, t, w); } void MinPolyInternal(GF2X& h, const GF2X& x, long m) { if (m < NTL_GF2X_BERMASS_CROSSOVER) { OldMinPolyInternal(h, x, m); return; } GF2X a, b; _NTL_GF2XMatrix M; SetCoeff(b, 2*m); CopyReverse(a, x, 2*m-1); HalfGCD(M, b, a, m+1); h = M(1,1); } NTL_END_IMPL ntl-11.5.1/src/GF2XFactoring.cpp0000644417616742025610000007545514064716022020033 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL long IterIrredTest(const GF2X& f) { long df = deg(f); if (df <= 0) return 0; if (df == 1) return 1; GF2XModulus F; build(F, f); GF2X h; SetX(h); SqrMod(h, h, F); long i, d, limit, limit_sqr; GF2X g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= df) { add(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { SqrMod(g, g, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& ff) { GF2X f = ff; if (IsZero(f)) LogicError("SquareFreeDecomp: bad args"); GF2X r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; p = 2; d = deg(r)/p; clear(f); for (k = 0; k <= d; k++) if (coeff(r, k*p) == 1) SetCoeff(f, k); m = m*p; } } while (!finished); } static void AddFactor(vec_pair_GF2X_long& factors, const GF2X& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(GF2X& f, vec_pair_GF2X_long& factors, const GF2XModulus& F, long limit, const vec_GF2X& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; GF2X t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); GF2X t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } static void TraceMap(GF2X& w, const GF2X& a, long d, const GF2XModulus& F) { GF2X y, z; y = a; z = a; long i; for (i = 1; i < d; i++) { SqrMod(z, z, F); add(y, y, z); } w = y; } const long GF2X_BlockingFactor = 40; void DDF(vec_pair_GF2X_long& factors, const GF2X& ff, long verbose) { GF2X f = ff; if (IsZero(f)) LogicError("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long GCDTableSize = GF2X_BlockingFactor; GF2XModulus F; build(F, f); long i, d, limit, old_n; GF2X g, X; vec_GF2X tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; SqrMod(g, X, F); d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); add(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(g, g, F); } SqrMod(g, g, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } static void EDFSplit(GF2X& f1, GF2X& f2, const GF2X& f, long d) { GF2X a, g; GF2XModulus F; build(F, f); long n = F.n; do { random(a, n); TraceMap(g, a, d, F); } while (deg(g) <= 0); GCD(f1, f, g); div(f2, f, f1); } static void RecEDF(vec_GF2X& factors, const GF2X& f, long d) { if (deg(f) == d) { append(factors, f); return; } GF2X f1, f2; EDFSplit(f1, f2, f, d); RecEDF(factors, f1, d); RecEDF(factors, f2, d); } void EDF(vec_GF2X& factors, const GF2X& ff, long d, long verbose) { GF2X f = ff; if (IsZero(f)) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { // factors are X and X+1 factors.SetLength(2); SetX(factors[0]); SetX(factors[1]); SetCoeff(factors[1], 0); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, d); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_GF2X& factors, const GF2X& ff, long verbose) { GF2X f = ff; if (IsZero(f)) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; vec_pair_GF2X_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } DDF(u, f, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } vec_GF2X v; long i; for (i = 0; i < u.length(); i++) { const GF2X& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF EDF(v, g, d, verbose); append(factors, v); } } } void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose) { if (IsZero(f)) LogicError("CanZass: bad args"); double t; vec_pair_GF2X_long sfd; vec_GF2X x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(GF2X& f, const vec_pair_GF2X_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); GF2X g; set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static void ConvertBits(GF2X& x, _ntl_ulong b) { clear(x); long i; for (i = NTL_BITS_PER_LONG-1; i >= 0; i--) if (b & (1UL << i)) SetCoeff(x, i); } void BuildIrred(GF2X& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } GF2X g; _ntl_ulong i; i = 0; do { if (i >> (NTL_BITS_PER_LONG-1)) ResourceError("BuildIrred: limit exceeded"); ConvertBits(g, 2*i+1); SetCoeff(g, n); i++; } while (!IterIrredTest(g)); f = g; } void BuildRandomIrred(GF2X& f, const GF2X& g) { GF2XModulus G; GF2X h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } static int GF2X_irred_tab[][3] = {{0,0,0}, {0,0,0}, {1,0,0}, {1,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {1,0,0}, {4,3,1}, {1,0,0}, {3,0,0}, {2,0,0}, {3,0,0}, {4,3,1}, {5,0,0}, {1,0,0}, {5,3,1}, {3,0,0}, {3,0,0}, {5,2,1}, {3,0,0}, {2,0,0}, {1,0,0}, {5,0,0}, {4,3,1}, {3,0,0}, {4,3,1}, {5,2,1}, {1,0,0}, {2,0,0}, {1,0,0}, {3,0,0}, {7,3,2}, {10,0,0}, {7,0,0}, {2,0,0}, {9,0,0}, {6,4,1}, {6,5,1}, {4,0,0}, {5,4,3}, {3,0,0}, {7,0,0}, {6,4,3}, {5,0,0}, {4,3,1}, {1,0,0}, {5,0,0}, {5,3,2}, {9,0,0}, {4,3,2}, {6,3,1}, {3,0,0}, {6,2,1}, {9,0,0}, {7,0,0}, {7,4,2}, {4,0,0}, {19,0,0}, {7,4,2}, {1,0,0}, {5,2,1}, {29,0,0}, {1,0,0}, {4,3,1}, {18,0,0}, {3,0,0}, {5,2,1}, {9,0,0}, {6,5,2}, {5,3,1}, {6,0,0}, {10,9,3}, {25,0,0}, {35,0,0}, {6,3,1}, {21,0,0}, {6,5,2}, {6,5,3}, {9,0,0}, {9,4,2}, {4,0,0}, {8,3,1}, {7,4,2}, {5,0,0}, {8,2,1}, {21,0,0}, {13,0,0}, {7,6,2}, {38,0,0}, {27,0,0}, {8,5,1}, {21,0,0}, {2,0,0}, {21,0,0}, {11,0,0}, {10,9,6}, {6,0,0}, {11,0,0}, {6,3,1}, {15,0,0}, {7,6,1}, {29,0,0}, {9,0,0}, {4,3,1}, {4,0,0}, {15,0,0}, {9,7,4}, {17,0,0}, {5,4,2}, {33,0,0}, {10,0,0}, {5,4,3}, {9,0,0}, {5,3,2}, {8,7,5}, {4,2,1}, {5,2,1}, {33,0,0}, {8,0,0}, {4,3,1}, {18,0,0}, {6,2,1}, {2,0,0}, {19,0,0}, {7,6,5}, {21,0,0}, {1,0,0}, {7,2,1}, {5,0,0}, {3,0,0}, {8,3,2}, {17,0,0}, {9,8,2}, {57,0,0}, {11,0,0}, {5,3,2}, {21,0,0}, {8,7,1}, {8,5,3}, {15,0,0}, {10,4,1}, {21,0,0}, {5,3,2}, {7,4,2}, {52,0,0}, {71,0,0}, {14,0,0}, {27,0,0}, {10,9,7}, {53,0,0}, {3,0,0}, {6,3,2}, {1,0,0}, {15,0,0}, {62,0,0}, {9,0,0}, {6,5,2}, {8,6,5}, {31,0,0}, {5,3,2}, {18,0,0}, {27,0,0}, {7,6,3}, {10,8,7}, {9,8,3}, {37,0,0}, {6,0,0}, {15,3,2}, {34,0,0}, {11,0,0}, {6,5,2}, {1,0,0}, {8,5,2}, {13,0,0}, {6,0,0}, {11,3,2}, {8,0,0}, {31,0,0}, {4,2,1}, {3,0,0}, {7,6,1}, {81,0,0}, {56,0,0}, {9,8,7}, {24,0,0}, {11,0,0}, {7,6,5}, {6,5,2}, {6,5,2}, {8,7,6}, {9,0,0}, {7,2,1}, {15,0,0}, {87,0,0}, {8,3,2}, {3,0,0}, {9,4,2}, {9,0,0}, {34,0,0}, {5,3,2}, {14,0,0}, {55,0,0}, {8,7,1}, {27,0,0}, {9,5,2}, {10,9,5}, {43,0,0}, {9,3,1}, {6,0,0}, {7,0,0}, {11,10,8}, {105,0,0}, {6,5,2}, {73,0,0}, {23,0,0}, {7,3,1}, {45,0,0}, {11,0,0}, {8,4,1}, {7,0,0}, {8,6,2}, {5,4,2}, {33,0,0}, {9,8,3}, {32,0,0}, {10,7,3}, {10,9,4}, {113,0,0}, {10,4,1}, {8,7,6}, {26,0,0}, {9,4,2}, {74,0,0}, {31,0,0}, {9,6,1}, {5,0,0}, {7,4,1}, {73,0,0}, {36,0,0}, {8,5,3}, {70,0,0}, {95,0,0}, {8,5,1}, {111,0,0}, {6,4,1}, {11,2,1}, {82,0,0}, {15,14,10}, {35,0,0}, {103,0,0}, {7,4,2}, {15,0,0}, {46,0,0}, {7,2,1}, {52,0,0}, {10,5,2}, {12,0,0}, {71,0,0}, {10,6,2}, {15,0,0}, {7,6,4}, {9,8,4}, {93,0,0}, {9,6,2}, {42,0,0}, {47,0,0}, {8,6,3}, {25,0,0}, {7,6,1}, {53,0,0}, {58,0,0}, {9,3,2}, {23,0,0}, {67,0,0}, {11,10,9}, {63,0,0}, {12,6,3}, {5,0,0}, {5,0,0}, {9,5,2}, {93,0,0}, {35,0,0}, {12,7,5}, {53,0,0}, {10,7,5}, {69,0,0}, {71,0,0}, {11,10,1}, {21,0,0}, {5,3,2}, {12,11,5}, {37,0,0}, {11,6,1}, {33,0,0}, {48,0,0}, {7,3,2}, {5,0,0}, {11,8,4}, {11,6,4}, {5,0,0}, {9,5,2}, {41,0,0}, {1,0,0}, {11,2,1}, {102,0,0}, {7,3,1}, {8,4,2}, {15,0,0}, {10,6,4}, {93,0,0}, {7,5,3}, {9,7,4}, {79,0,0}, {15,0,0}, {10,9,1}, {63,0,0}, {7,4,2}, {45,0,0}, {36,0,0}, {4,3,1}, {31,0,0}, {67,0,0}, {10,3,1}, {51,0,0}, {10,5,2}, {10,3,1}, {34,0,0}, {8,3,1}, {50,0,0}, {99,0,0}, {10,6,2}, {89,0,0}, {2,0,0}, {5,2,1}, {10,7,2}, {7,4,1}, {55,0,0}, {4,3,1}, {16,10,7}, {45,0,0}, {10,8,6}, {125,0,0}, {75,0,0}, {7,2,1}, {22,0,0}, {63,0,0}, {11,10,3}, {103,0,0}, {6,5,2}, {53,0,0}, {34,0,0}, {13,11,6}, {69,0,0}, {99,0,0}, {6,5,1}, {10,9,7}, {11,10,2}, {57,0,0}, {68,0,0}, {5,3,2}, {7,4,1}, {63,0,0}, {8,5,3}, {9,0,0}, {9,6,5}, {29,0,0}, {21,0,0}, {7,3,2}, {91,0,0}, {139,0,0}, {8,3,2}, {111,0,0}, {8,7,2}, {8,6,5}, {16,0,0}, {8,7,5}, {41,0,0}, {43,0,0}, {10,8,5}, {47,0,0}, {5,2,1}, {81,0,0}, {90,0,0}, {12,3,2}, {6,0,0}, {83,0,0}, {8,7,1}, {159,0,0}, {10,9,5}, {9,0,0}, {28,0,0}, {13,10,6}, {7,0,0}, {135,0,0}, {11,6,5}, {25,0,0}, {12,7,6}, {7,6,2}, {26,0,0}, {5,3,2}, {152,0,0}, {171,0,0}, {9,8,5}, {65,0,0}, {13,8,2}, {141,0,0}, {71,0,0}, {5,3,2}, {87,0,0}, {10,4,3}, {12,10,3}, {147,0,0}, {10,7,6}, {13,0,0}, {102,0,0}, {9,5,2}, {107,0,0}, {199,0,0}, {15,5,4}, {7,0,0}, {5,4,2}, {149,0,0}, {25,0,0}, {9,7,2}, {12,0,0}, {63,0,0}, {11,6,5}, {105,0,0}, {10,8,7}, {14,6,1}, {120,0,0}, {13,4,3}, {33,0,0}, {12,11,5}, {12,9,5}, {165,0,0}, {6,2,1}, {65,0,0}, {49,0,0}, {4,3,1}, {7,0,0}, {7,5,2}, {10,6,1}, {81,0,0}, {7,6,4}, {105,0,0}, {73,0,0}, {11,6,4}, {134,0,0}, {47,0,0}, {16,10,1}, {6,5,4}, {15,6,4}, {8,6,1}, {38,0,0}, {18,9,6}, {16,0,0}, {203,0,0}, {12,5,2}, {19,0,0}, {7,6,1}, {73,0,0}, {93,0,0}, {19,18,13}, {31,0,0}, {14,11,6}, {11,6,1}, {27,0,0}, {9,5,2}, {9,0,0}, {1,0,0}, {11,3,2}, {200,0,0}, {191,0,0}, {9,8,4}, {9,0,0}, {16,15,7}, {121,0,0}, {104,0,0}, {15,9,6}, {138,0,0}, {9,6,5}, {9,6,4}, {105,0,0}, {17,16,6}, {81,0,0}, {94,0,0}, {4,3,1}, {83,0,0}, {219,0,0}, {11,6,3}, {7,0,0}, {10,5,3}, {17,0,0}, {76,0,0}, {16,5,2}, {78,0,0}, {155,0,0}, {11,6,5}, {27,0,0}, {5,4,2}, {8,5,4}, {3,0,0}, {15,14,6}, {156,0,0}, {23,0,0}, {13,6,3}, {9,0,0}, {8,7,3}, {69,0,0}, {10,0,0}, {8,5,2}, {26,0,0}, {67,0,0}, {14,7,4}, {21,0,0}, {12,10,2}, {33,0,0}, {79,0,0}, {15,11,2}, {32,0,0}, {39,0,0}, {13,6,2}, {167,0,0}, {6,4,1}, {97,0,0}, {47,0,0}, {11,6,2}, {42,0,0}, {10,7,3}, {10,5,4}, {1,0,0}, {4,3,2}, {161,0,0}, {8,6,2}, {7,5,3}, {94,0,0}, {195,0,0}, {10,5,4}, {9,0,0}, {13,10,4}, {8,6,1}, {16,0,0}, {8,3,1}, {122,0,0}, {8,2,1}, {13,7,4}, {10,5,3}, {16,4,3}, {193,0,0}, {135,0,0}, {19,16,9}, {39,0,0}, {10,8,7}, {10,9,4}, {153,0,0}, {7,6,5}, {73,0,0}, {34,0,0}, {11,9,6}, {71,0,0}, {11,4,2}, {14,7,3}, {163,0,0}, {11,6,1}, {153,0,0}, {28,0,0}, {15,7,6}, {77,0,0}, {67,0,0}, {10,5,2}, {12,8,1}, {10,6,4}, {13,0,0}, {146,0,0}, {13,4,3}, {25,0,0}, {23,22,16}, {12,9,7}, {237,0,0}, {13,7,6}, {85,0,0}, {130,0,0}, {14,13,3}, {88,0,0}, {7,5,2}, {11,6,1}, {35,0,0}, {10,4,3}, {93,0,0}, {9,6,4}, {13,6,3}, {86,0,0}, {19,0,0}, {9,2,1}, {273,0,0}, {14,12,9}, {7,6,1}, {30,0,0}, {9,5,2}, {201,0,0}, {215,0,0}, {6,4,3}, {105,0,0}, {10,7,5}, {165,0,0}, {105,0,0}, {19,13,6}, {31,0,0}, {127,0,0}, {10,4,2}, {81,0,0}, {19,10,4}, {45,0,0}, {211,0,0}, {19,10,3}, {200,0,0}, {295,0,0}, {9,8,5}, {9,0,0}, {12,6,5}, {297,0,0}, {68,0,0}, {11,6,5}, {133,0,0}, {251,0,0}, {13,8,4}, {223,0,0}, {6,5,2}, {7,4,2}, {307,0,0}, {9,2,1}, {101,0,0}, {39,0,0}, {14,10,4}, {217,0,0}, {14,9,1}, {6,5,1}, {16,0,0}, {14,3,2}, {11,0,0}, {119,0,0}, {11,3,2}, {11,6,5}, {11,8,4}, {249,0,0}, {5,0,0}, {13,3,1}, {37,0,0}, {3,0,0}, {14,0,0}, {93,0,0}, {10,8,7}, {33,0,0}, {88,0,0}, {7,5,4}, {38,0,0}, {55,0,0}, {15,4,2}, {11,0,0}, {12,11,4}, {21,0,0}, {107,0,0}, {11,9,8}, {33,0,0}, {10,7,2}, {18,7,3}, {147,0,0}, {5,4,2}, {153,0,0}, {15,0,0}, {11,6,5}, {28,0,0}, {11,7,4}, {6,3,1}, {31,0,0}, {8,4,3}, {15,5,3}, {66,0,0}, {23,16,9}, {11,9,3}, {171,0,0}, {11,6,1}, {209,0,0}, {4,3,1}, {197,0,0}, {13,0,0}, {19,14,6}, {14,0,0}, {79,0,0}, {13,6,2}, {299,0,0}, {15,8,2}, {169,0,0}, {177,0,0}, {23,10,2}, {267,0,0}, {215,0,0}, {15,10,1}, {75,0,0}, {16,4,2}, {37,0,0}, {12,7,1}, {8,3,2}, {17,0,0}, {12,11,8}, {15,8,5}, {15,0,0}, {4,3,1}, {13,12,4}, {92,0,0}, {5,4,3}, {41,0,0}, {23,0,0}, {7,4,1}, {183,0,0}, {16,7,1}, {165,0,0}, {150,0,0}, {9,6,4}, {9,0,0}, {231,0,0}, {16,10,4}, {207,0,0}, {9,6,5}, {5,0,0}, {180,0,0}, {4,3,2}, {58,0,0}, {147,0,0}, {8,6,2}, {343,0,0}, {8,7,2}, {11,6,1}, {44,0,0}, {13,8,6}, {5,0,0}, {347,0,0}, {18,16,8}, {135,0,0}, {9,8,3}, {85,0,0}, {90,0,0}, {13,11,1}, {258,0,0}, {351,0,0}, {10,6,4}, {19,0,0}, {7,6,1}, {309,0,0}, {18,0,0}, {13,10,3}, {158,0,0}, {19,0,0}, {12,10,1}, {45,0,0}, {7,6,1}, {233,0,0}, {98,0,0}, {11,6,5}, {3,0,0}, {83,0,0}, {16,14,9}, {6,5,3}, {9,7,4}, {22,19,9}, {168,0,0}, {19,17,4}, {120,0,0}, {14,5,2}, {17,15,6}, {7,0,0}, {10,8,6}, {185,0,0}, {93,0,0}, {15,14,7}, {29,0,0}, {375,0,0}, {10,8,3}, {13,0,0}, {17,16,2}, {329,0,0}, {68,0,0}, {13,9,6}, {92,0,0}, {12,10,3}, {7,6,3}, {17,10,3}, {5,2,1}, {9,6,1}, {30,0,0}, {9,7,3}, {253,0,0}, {143,0,0}, {7,4,1}, {9,4,1}, {12,10,4}, {53,0,0}, {25,0,0}, {9,7,1}, {217,0,0}, {15,13,9}, {14,9,2}, {75,0,0}, {8,7,2}, {21,0,0}, {7,0,0}, {14,3,2}, {15,0,0}, {159,0,0}, {12,10,8}, {29,0,0}, {10,3,1}, {21,0,0}, {333,0,0}, {11,8,2}, {52,0,0}, {119,0,0}, {16,9,7}, {123,0,0}, {15,11,2}, {17,0,0}, {9,0,0}, {11,6,4}, {38,0,0}, {255,0,0}, {12,10,7}, {189,0,0}, {4,3,1}, {17,10,7}, {49,0,0}, {13,5,2}, {149,0,0}, {15,0,0}, {14,7,5}, {10,9,2}, {8,6,5}, {61,0,0}, {54,0,0}, {11,5,1}, {144,0,0}, {47,0,0}, {11,10,7}, {105,0,0}, {2,0,0}, {105,0,0}, {136,0,0}, {11,4,1}, {253,0,0}, {111,0,0}, {13,10,5}, {159,0,0}, {10,7,1}, {7,5,3}, {29,0,0}, {19,10,3}, {119,0,0}, {207,0,0}, {17,15,4}, {35,0,0}, {14,0,0}, {349,0,0}, {6,3,2}, {21,10,6}, {1,0,0}, {75,0,0}, {9,5,2}, {145,0,0}, {11,7,6}, {301,0,0}, {378,0,0}, {13,3,1}, {352,0,0}, {12,7,4}, {12,8,1}, {149,0,0}, {6,5,4}, {12,9,8}, {11,0,0}, {15,7,5}, {78,0,0}, {99,0,0}, {17,16,12}, {173,0,0}, {8,7,1}, {13,9,8}, {147,0,0}, {19,18,10}, {127,0,0}, {183,0,0}, {12,4,1}, {31,0,0}, {11,8,6}, {173,0,0}, {12,0,0}, {7,5,3}, {113,0,0}, {207,0,0}, {18,15,5}, {1,0,0}, {13,7,6}, {21,0,0}, {35,0,0}, {12,7,2}, {117,0,0}, {123,0,0}, {12,10,2}, {143,0,0}, {14,4,1}, {15,9,7}, {204,0,0}, {7,5,1}, {91,0,0}, {4,2,1}, {8,6,3}, {183,0,0}, {12,10,7}, {77,0,0}, {36,0,0}, {14,9,6}, {221,0,0}, {7,6,5}, {16,14,13}, {31,0,0}, {16,15,7}, {365,0,0}, {403,0,0}, {10,3,2}, {11,4,3}, {31,0,0}, {10,9,4}, {177,0,0}, {16,6,1}, {22,6,5}, {417,0,0}, {15,13,12}, {217,0,0}, {207,0,0}, {7,5,4}, {10,7,1}, {11,6,1}, {45,0,0}, {24,0,0}, {12,11,9}, {77,0,0}, {21,20,13}, {9,6,5}, {189,0,0}, {8,3,2}, {13,12,10}, {260,0,0}, {16,9,7}, {168,0,0}, {131,0,0}, {7,6,3}, {305,0,0}, {10,9,6}, {13,9,4}, {143,0,0}, {12,9,3}, {18,0,0}, {15,8,5}, {20,9,6}, {103,0,0}, {15,4,2}, {201,0,0}, {36,0,0}, {9,5,2}, {31,0,0}, {11,7,2}, {6,2,1}, {7,0,0}, {13,6,4}, {9,8,7}, {19,0,0}, {17,10,6}, {15,0,0}, {9,3,1}, {178,0,0}, {8,7,6}, {12,6,5}, {177,0,0}, {230,0,0}, {24,9,3}, {222,0,0}, {3,0,0}, {16,13,12}, {121,0,0}, {10,4,2}, {161,0,0}, {39,0,0}, {17,15,13}, {62,0,0}, {223,0,0}, {15,12,2}, {65,0,0}, {12,6,3}, {101,0,0}, {59,0,0}, {5,4,3}, {17,0,0}, {5,3,2}, {13,8,3}, {10,9,7}, {12,8,2}, {5,4,3}, {75,0,0}, {19,17,8}, {55,0,0}, {99,0,0}, {10,7,4}, {115,0,0}, {9,8,6}, {385,0,0}, {186,0,0}, {15,6,3}, {9,4,1}, {12,10,5}, {10,8,1}, {135,0,0}, {5,2,1}, {317,0,0}, {7,0,0}, {19,6,1}, {294,0,0}, {35,0,0}, {13,12,6}, {119,0,0}, {98,0,0}, {93,0,0}, {68,0,0}, {21,15,3}, {108,0,0}, {75,0,0}, {12,6,5}, {411,0,0}, {12,7,2}, {13,7,2}, {21,0,0}, {15,10,8}, {412,0,0}, {439,0,0}, {10,7,6}, {41,0,0}, {13,9,6}, {8,5,2}, {10,0,0}, {15,7,2}, {141,0,0}, {159,0,0}, {13,12,10}, {291,0,0}, {10,9,1}, {105,0,0}, {24,0,0}, {11,2,1}, {198,0,0}, {27,0,0}, {6,3,1}, {439,0,0}, {10,3,1}, {49,0,0}, {168,0,0}, {13,11,9}, {463,0,0}, {10,9,3}, {13,9,8}, {15,8,3}, {18,16,8}, {15,14,11}, {7,0,0}, {19,9,8}, {12,6,3}, {7,4,3}, {15,14,5}, {8,6,3}, {10,9,7}, {361,0,0}, {230,0,0}, {15,9,6}, {24,0,0}, {407,0,0}, {16,7,2}, {189,0,0}, {62,0,0}, {189,0,0}, {112,0,0}, {22,21,10}, {91,0,0}, {79,0,0}, {12,10,5}, {23,0,0}, {7,6,1}, {57,0,0}, {139,0,0}, {24,15,6}, {14,0,0}, {83,0,0}, {16,9,1}, {35,0,0}, {9,7,4}, {117,0,0}, {65,0,0}, {21,9,6}, {21,0,0}, {195,0,0}, {23,11,10}, {327,0,0}, {17,14,3}, {417,0,0}, {13,0,0}, {15,8,6}, {107,0,0}, {19,10,6}, {18,15,3}, {59,0,0}, {12,10,4}, {9,7,5}, {283,0,0}, {13,9,6}, {62,0,0}, {427,0,0}, {14,7,3}, {8,7,4}, {15,8,3}, {105,0,0}, {27,0,0}, {7,3,1}, {103,0,0}, {551,0,0}, {10,6,1}, {6,4,1}, {11,6,4}, {129,0,0}, {9,0,0}, {9,4,2}, {277,0,0}, {31,0,0}, {13,12,5}, {141,0,0}, {12,7,3}, {357,0,0}, {7,2,1}, {11,9,7}, {227,0,0}, {131,0,0}, {7,6,3}, {23,0,0}, {20,17,3}, {13,4,1}, {90,0,0}, {15,3,2}, {241,0,0}, {75,0,0}, {13,6,1}, {307,0,0}, {8,7,3}, {245,0,0}, {66,0,0}, {15,11,2}, {365,0,0}, {18,16,11}, {11,10,1}, {19,0,0}, {8,6,1}, {189,0,0}, {133,0,0}, {12,7,2}, {114,0,0}, {27,0,0}, {6,5,1}, {15,5,2}, {17,14,5}, {133,0,0}, {476,0,0}, {11,9,3}, {16,0,0}, {375,0,0}, {15,8,6}, {25,0,0}, {17,11,6}, {77,0,0}, {87,0,0}, {5,3,2}, {134,0,0}, {171,0,0}, {13,8,4}, {75,0,0}, {8,3,1}, {233,0,0}, {196,0,0}, {9,8,7}, {173,0,0}, {15,14,12}, {13,6,5}, {281,0,0}, {9,8,2}, {405,0,0}, {114,0,0}, {15,9,6}, {171,0,0}, {287,0,0}, {8,4,2}, {43,0,0}, {4,2,1}, {513,0,0}, {273,0,0}, {11,10,6}, {118,0,0}, {243,0,0}, {14,7,1}, {203,0,0}, {9,5,2}, {257,0,0}, {302,0,0}, {27,25,9}, {393,0,0}, {91,0,0}, {12,10,6}, {413,0,0}, {15,14,9}, {18,16,1}, {255,0,0}, {12,9,7}, {234,0,0}, {167,0,0}, {16,13,10}, {27,0,0}, {15,6,2}, {433,0,0}, {105,0,0}, {25,10,2}, {151,0,0}, {427,0,0}, {13,9,8}, {49,0,0}, {10,6,4}, {153,0,0}, {4,0,0}, {17,7,5}, {54,0,0}, {203,0,0}, {16,15,1}, {16,14,7}, {13,6,1}, {25,0,0}, {14,0,0}, {15,5,3}, {187,0,0}, {15,13,10}, {13,10,5}, {97,0,0}, {11,10,9}, {19,10,4}, {589,0,0}, {31,30,2}, {289,0,0}, {9,6,4}, {11,8,6}, {21,0,0}, {7,4,1}, {7,4,2}, {77,0,0}, {5,3,2}, {119,0,0}, {7,0,0}, {9,5,2}, {345,0,0}, {17,10,8}, {333,0,0}, {17,0,0}, {16,9,7}, {168,0,0}, {15,13,4}, {11,10,1}, {217,0,0}, {18,11,10}, {189,0,0}, {216,0,0}, {12,7,5}, {229,0,0}, {231,0,0}, {12,9,3}, {223,0,0}, {10,9,1}, {153,0,0}, {470,0,0}, {23,16,6}, {99,0,0}, {10,4,3}, {9,8,4}, {12,10,1}, {14,9,6}, {201,0,0}, {38,0,0}, {15,14,2}, {198,0,0}, {399,0,0}, {14,11,5}, {75,0,0}, {11,10,1}, {77,0,0}, {16,12,8}, {20,17,15}, {326,0,0}, {39,0,0}, {14,12,9}, {495,0,0}, {8,3,2}, {333,0,0}, {476,0,0}, {15,14,2}, {164,0,0}, {19,0,0}, {12,4,2}, {8,6,3}, {13,12,3}, {12,11,5}, {129,0,0}, {12,9,3}, {52,0,0}, {10,8,3}, {17,16,2}, {337,0,0}, {12,9,3}, {397,0,0}, {277,0,0}, {21,11,3}, {73,0,0}, {11,6,1}, {7,5,4}, {95,0,0}, {11,3,2}, {617,0,0}, {392,0,0}, {8,3,2}, {75,0,0}, {315,0,0}, {15,6,4}, {125,0,0}, {6,5,2}, {15,9,7}, {348,0,0}, {15,6,1}, {553,0,0}, {6,3,2}, {10,9,7}, {553,0,0}, {14,10,4}, {237,0,0}, {39,0,0}, {17,14,6}, {371,0,0}, {255,0,0}, {8,4,1}, {131,0,0}, {14,6,1}, {117,0,0}, {98,0,0}, {5,3,2}, {56,0,0}, {655,0,0}, {9,5,2}, {239,0,0}, {11,8,4}, {1,0,0}, {134,0,0}, {15,9,5}, {88,0,0}, {10,5,3}, {10,9,4}, {181,0,0}, {15,11,2}, {609,0,0}, {52,0,0}, {19,18,10}, {100,0,0}, {7,6,3}, {15,8,2}, {183,0,0}, {18,7,6}, {10,9,2}, {130,0,0}, {11,5,1}, {12,0,0}, {219,0,0}, {13,10,7}, {11,0,0}, {19,9,4}, {129,0,0}, {3,0,0}, {17,15,5}, {300,0,0}, {17,13,9}, {14,6,5}, {97,0,0}, {13,8,3}, {601,0,0}, {55,0,0}, {8,3,1}, {92,0,0}, {127,0,0}, {12,11,2}, {81,0,0}, {15,10,8}, {13,2,1}, {47,0,0}, {14,13,6}, {194,0,0}, {383,0,0}, {25,14,11}, {125,0,0}, {20,19,16}, {429,0,0}, {282,0,0}, {10,9,6}, {342,0,0}, {5,3,2}, {15,9,4}, {33,0,0}, {9,4,2}, {49,0,0}, {15,0,0}, {11,6,2}, {28,0,0}, {103,0,0}, {18,17,8}, {27,0,0}, {11,6,5}, {33,0,0}, {17,0,0}, {11,10,6}, {387,0,0}, {363,0,0}, {15,10,9}, {83,0,0}, {7,6,4}, {357,0,0}, {13,12,4}, {14,13,7}, {322,0,0}, {395,0,0}, {16,5,1}, {595,0,0}, {13,10,3}, {421,0,0}, {195,0,0}, {11,3,2}, {13,0,0}, {16,12,3}, {14,3,1}, {315,0,0}, {26,10,5}, {297,0,0}, {52,0,0}, {9,4,2}, {314,0,0}, {243,0,0}, {16,14,9}, {185,0,0}, {12,5,3}, {13,5,2}, {575,0,0}, {12,9,3}, {39,0,0}, {311,0,0}, {13,5,2}, {181,0,0}, {20,18,14}, {49,0,0}, {25,0,0}, {11,4,1}, {77,0,0}, {17,11,10}, {15,14,8}, {21,0,0}, {17,10,5}, {69,0,0}, {49,0,0}, {11,10,2}, {32,0,0}, {411,0,0}, {21,16,3}, {11,7,4}, {22,10,3}, {85,0,0}, {140,0,0}, {9,8,6}, {252,0,0}, {279,0,0}, {9,5,2}, {307,0,0}, {17,10,4}, {13,12,9}, {94,0,0}, {13,11,4}, {49,0,0}, {17,11,10}, {16,12,5}, {25,0,0}, {6,5,2}, {12,5,1}, {80,0,0}, {8,3,2}, {246,0,0}, {11,5,2}, {11,10,2}, {599,0,0}, {18,12,10}, {189,0,0}, {278,0,0}, {10,9,3}, {399,0,0}, {299,0,0}, {13,10,6}, {277,0,0}, {13,10,6}, {69,0,0}, {220,0,0}, {13,10,3}, {229,0,0}, {18,11,10}, {16,15,1}, {27,0,0}, {18,9,3}, {473,0,0}, {373,0,0}, {18,17,7}, {60,0,0}, {207,0,0}, {13,9,8}, {22,20,13}, {25,18,7}, {225,0,0}, {404,0,0}, {21,6,2}, {46,0,0}, {6,2,1}, {17,12,6}, {75,0,0}, {4,2,1}, {365,0,0}, {445,0,0}, {11,7,1}, {44,0,0}, {10,8,5}, {12,5,2}, {63,0,0}, {17,4,2}, {189,0,0}, {557,0,0}, {19,12,2}, {252,0,0}, {99,0,0}, {10,8,5}, {65,0,0}, {14,9,3}, {9,0,0}, {119,0,0}, {8,5,2}, {339,0,0}, {95,0,0}, {12,9,7}, {7,0,0}, {13,10,2}, {77,0,0}, {127,0,0}, {21,10,7}, {319,0,0}, {667,0,0}, {17,10,3}, {501,0,0}, {18,12,9}, {9,8,5}, {17,0,0}, {20,9,2}, {341,0,0}, {731,0,0}, {7,6,5}, {647,0,0}, {10,4,2}, {121,0,0}, {20,0,0}, {21,19,13}, {574,0,0}, {399,0,0}, {15,10,7}, {85,0,0}, {16,8,3}, {169,0,0}, {15,0,0}, {12,7,5}, {568,0,0}, {10,7,1}, {18,2,1}, {3,0,0}, {14,3,2}, {13,7,3}, {643,0,0}, {14,11,1}, {548,0,0}, {783,0,0}, {14,11,1}, {317,0,0}, {7,6,4}, {153,0,0}, {87,0,0}, {15,13,1}, {231,0,0}, {11,5,3}, {18,13,7}, {771,0,0}, {30,20,11}, {15,6,3}, {103,0,0}, {13,4,3}, {182,0,0}, {211,0,0}, {17,6,1}, {27,0,0}, {13,12,10}, {15,14,10}, {17,0,0}, {13,11,5}, {69,0,0}, {11,5,1}, {18,6,1}, {603,0,0}, {10,4,2}, {741,0,0}, {668,0,0}, {17,15,3}, {147,0,0}, {227,0,0}, {15,10,9}, {37,0,0}, {16,6,1}, {173,0,0}, {427,0,0}, {7,5,1}, {287,0,0}, {231,0,0}, {20,15,10}, {18,9,1}, {14,12,5}, {16,5,1}, {310,0,0}, {18,13,1}, {434,0,0}, {579,0,0}, {18,13,8}, {45,0,0}, {12,8,3}, {16,9,5}, {53,0,0}, {19,15,10}, {16,0,0}, {17,6,5}, {17,10,1}, {37,0,0}, {17,10,9}, {21,13,7}, {99,0,0}, {17,9,6}, {176,0,0}, {271,0,0}, {18,17,13}, {459,0,0}, {21,17,10}, {6,5,2}, {202,0,0}, {5,4,3}, {90,0,0}, {755,0,0}, {15,7,2}, {363,0,0}, {8,4,2}, {129,0,0}, {20,0,0}, {11,6,2}, {135,0,0}, {15,8,7}, {14,13,2}, {10,4,3}, {24,13,10}, {19,14,11}, {31,0,0}, {15,8,6}, {758,0,0}, {16,11,5}, {16,5,1}, {359,0,0}, {23,18,17}, {501,0,0}, {29,0,0}, {15,6,3}, {201,0,0}, {459,0,0}, {12,10,7}, {225,0,0}, {22,17,13}, {24,22,5}, {161,0,0}, {14,11,3}, {52,0,0}, {19,17,6}, {21,14,12}, {93,0,0}, {13,10,3}, {201,0,0}, {178,0,0}, {15,12,5}, {250,0,0}, {7,6,4}, {17,13,6}, {221,0,0}, {13,11,8}, {17,14,9}, {113,0,0}, {17,14,10}, {300,0,0}, {39,0,0}, {18,13,3}, {261,0,0}, {15,14,8}, {753,0,0}, {8,4,3}, {11,10,5}, {94,0,0}, {15,13,1}, {10,4,2}, {14,11,10}, {8,6,2}, {461,0,0}, {418,0,0}, {19,14,6}, {403,0,0}, {267,0,0}, {10,9,2}, {259,0,0}, {20,4,3}, {869,0,0}, {173,0,0}, {19,18,2}, {369,0,0}, {255,0,0}, {22,12,9}, {567,0,0}, {20,11,7}, {457,0,0}, {482,0,0}, {6,3,2}, {775,0,0}, {19,17,6}, {6,4,3}, {99,0,0}, {15,14,8}, {6,5,2}, {165,0,0}, {8,3,2}, {13,12,10}, {25,21,17}, {17,14,9}, {105,0,0}, {17,15,14}, {10,3,2}, {250,0,0}, {25,6,5}, {327,0,0}, {279,0,0}, {13,6,5}, {371,0,0}, {15,9,4}, {117,0,0}, {486,0,0}, {10,9,3}, {217,0,0}, {635,0,0}, {30,27,17}, {457,0,0}, {16,6,2}, {57,0,0}, {439,0,0}, {23,21,6}, {214,0,0}, {20,13,6}, {20,16,1}, {819,0,0}, {15,11,8}, {593,0,0}, {190,0,0}, {17,14,3}, {114,0,0}, {21,18,3}, {10,5,2}, {12,9,5}, {8,6,3}, {69,0,0}, {312,0,0}, {22,5,2}, {502,0,0}, {843,0,0}, {15,10,3}, {747,0,0}, {6,5,2}, {101,0,0}, {123,0,0}, {19,16,9}, {521,0,0}, {171,0,0}, {16,7,2}, {12,6,5}, {22,21,20}, {545,0,0}, {163,0,0}, {23,18,1}, {479,0,0}, {495,0,0}, {13,6,5}, {11,0,0}, {17,5,2}, {18,8,1}, {684,0,0}, {7,5,1}, {9,0,0}, {18,11,3}, {22,20,13}, {273,0,0}, {4,3,2}, {381,0,0}, {51,0,0}, {18,13,7}, {518,0,0}, {9,5,1}, {14,12,3}, {243,0,0}, {21,17,2}, {53,0,0}, {836,0,0}, {21,10,2}, {66,0,0}, {12,10,7}, {13,9,8}, {339,0,0}, {16,11,5}, {901,0,0}, {180,0,0}, {16,13,3}, {49,0,0}, {6,3,2}, {15,4,1}, {16,13,6}, {18,15,12}, {885,0,0}, {39,0,0}, {11,9,4}, {688,0,0}, {16,15,7}, {13,10,6}, {13,0,0}, {25,23,12}, {149,0,0}, {260,0,0}, {11,9,1}, {53,0,0}, {11,0,0}, {12,4,2}, {9,7,5}, {11,8,1}, {121,0,0}, {261,0,0}, {10,5,2}, {199,0,0}, {20,4,3}, {17,9,2}, {13,9,4}, {12,8,7}, {253,0,0}, {174,0,0}, {15,4,2}, {370,0,0}, {9,6,1}, {16,10,9}, {669,0,0}, {20,10,9}, {833,0,0}, {353,0,0}, {17,13,2}, {29,0,0}, {371,0,0}, {9,8,5}, {8,7,1}, {19,8,7}, {12,11,10}, {873,0,0}, {26,11,2}, {12,9,1}, {10,7,2}, {13,6,1}, {235,0,0}, {26,24,19}, {733,0,0}, {778,0,0}, {12,11,1}, {344,0,0}, {931,0,0}, {16,6,4}, {945,0,0}, {21,19,14}, {18,13,11}, {67,0,0}, {20,15,10}, {462,0,0}, {14,5,1}, {10,9,6}, {18,11,10}, {16,9,7}, {477,0,0}, {105,0,0}, {11,3,2}, {468,0,0}, {23,16,15}, {16,15,6}, {327,0,0}, {23,10,4}, {357,0,0}, {25,0,0}, {17,16,7}, {31,0,0}, {7,5,2}, {16,7,6}, {277,0,0}, {14,13,6}, {413,0,0}, {103,0,0}, {15,10,1}, {231,0,0}, {747,0,0}, {5,2,1}, {113,0,0}, {20,10,7}, {15,9,6}, {11,0,0}, {27,22,18}, {91,0,0}, {51,0,0}, {18,13,12}, {603,0,0}, {10,7,3}, {9,0,0}, {121,0,0}, {15,14,6}, {17,0,0}, {16,11,2}, {23,15,6}, {279,0,0}, {16,12,6}, {89,0,0}, {371,0,0}, {17,15,2}, {771,0,0}, {99,0,0}, {7,6,3}, {21,0,0}, {10,7,5}, {801,0,0}, {26,0,0}, {25,19,14}, {175,0,0}, {10,7,2}, {20,5,4}, {12,11,1}, {22,5,1}, {165,0,0}, {841,0,0}, {25,19,17}, {238,0,0}, {11,8,6}, {22,21,4}, {33,0,0}, {8,7,6}, {14,9,2}, {113,0,0}, {13,11,5}, {311,0,0}, {891,0,0}, {20,16,14}, {555,0,0}, {23,14,8}, {133,0,0}, {546,0,0}, {6,3,2}, {103,0,0}, {15,0,0}, {10,7,3}, {307,0,0}, {14,10,1}, {15,12,2}, {367,0,0}, {13,10,6}, {169,0,0}, {22,21,11}, {12,10,8}, {441,0,0}, {17,12,7}, {917,0,0}, {205,0,0}, {26,23,13}, {54,0,0}, {459,0,0}, {17,15,4}, {19,15,4}, {5,4,2}, {9,7,6}, {42,0,0}, {21,15,7}, {330,0,0}, {20,7,3}, {20,7,2}, {81,0,0}, {19,14,1}, {349,0,0}, {165,0,0}, {40,35,9}, {274,0,0}, {475,0,0}, {11,10,3}, {93,0,0}, {12,7,4}, {13,12,2}, {386,0,0}, {7,6,2}, {881,0,0}, {143,0,0}, {9,8,4}, {71,0,0}, {19,18,3}, {16,11,6}, {155,0,0}, {7,2,1}, {735,0,0}, {16,8,7}, {9,7,4}, {45,0,0}, {7,6,4}, {12,11,3}, {3,0,0}, {19,14,13} }; static long FindTrinom(long n) { if (n < 2) LogicError("tri--bad n"); long k; for (k = 1; k <= n/2; k++) if (IterIrredTest(1 + GF2X(k,1) + GF2X(n,1))) return k; return 0; } static long FindPent(long n, long& kk2, long& kk1) { if (n < 4) LogicError("pent--bad n"); long k1, k2, k3; for (k3 = 3; k3 < n; k3++) for (k2 = 2; k2 < k3; k2++) for (k1 = 1; k1 < k2; k1++) if (IterIrredTest(1+GF2X(k1,1)+GF2X(k2,1)+GF2X(k3,1)+GF2X(n,1))) { kk2 = k2; kk1 = k1; return k3; } return 0; } void BuildSparseIrred(GF2X& f, long n) { if (n <= 0) LogicError("SparseIrred: n <= 0"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildSparseIrred"); if (n == 1) { SetX(f); return; } if (n <= 2048) { if (GF2X_irred_tab[n][1] == 0) { clear(f); SetCoeff(f, n); SetCoeff(f, GF2X_irred_tab[n][0]); SetCoeff(f, 0); } else { clear(f); SetCoeff(f, n); SetCoeff(f, GF2X_irred_tab[n][0]); SetCoeff(f, GF2X_irred_tab[n][1]); SetCoeff(f, GF2X_irred_tab[n][2]); SetCoeff(f, 0); } return; } long k3, k2, k1; k3 = FindTrinom(n); if (k3) { clear(f); SetCoeff(f, n); SetCoeff(f, k3); SetCoeff(f, 0); return; } k3 = FindPent(n, k2, k1); if (k3) { clear(f); SetCoeff(f, n); SetCoeff(f, k3); SetCoeff(f, k2); SetCoeff(f, k1); SetCoeff(f, 0); return; } // the following is probably of only theoretical value... // it is reasonable to conjecture that for all n >= 2, // there is either an irreducible trinomial or pentanomial // of degree n. BuildIrred(f, n); } NTL_END_IMPL ntl-11.5.1/src/GF2XVec.cpp0000644417616742025610000000232214064716022016613 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void GF2XVec::SetSize(long n, long d) { if (n < 0 || d <= 0) LogicError("bad args to GF2XVec::SetSize()"); if (v) LogicError("illegal GF2XVec initialization"); if (n == 0) { len = n; bsize = d; return; } GF2XVec tmp; tmp.len = 0; tmp.bsize = d; tmp.v = (GF2X*) NTL_SNS_MALLOC(n, sizeof(GF2X), 0); if (!tmp.v) MemoryError(); long i = 0; long m; long j; while (i < n) { m = WV_BlockConstructAlloc(tmp.v[i].xrep, d, n-i); for (j = 1; j < m; j++) WV_BlockConstructSet(tmp.v[i].xrep, tmp.v[i+j].xrep, j); i += m; tmp.len = i; } tmp.swap(*this); } void GF2XVec::kill() { long n = len; long i = 0; while (i < n) { long m = WV_BlockDestroy(v[i].xrep); i += m; } len = 0; bsize = 0; if (v) { free(v); v = 0; } } GF2XVec& GF2XVec::operator=(const GF2XVec& a) { if (this == &a) return *this; GF2XVec tmp(a); tmp.swap(*this); return *this; } GF2XVec::GF2XVec(const GF2XVec& a) : v(0), len(0), bsize(0) { SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; } NTL_END_IMPL ntl-11.5.1/src/HNF.cpp0000644417616742025610000000451214064716022016065 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL // This implements a variation of an algorithm in // [P. Domich, R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. // I started with the description in Henri Cohen's book, but had to modify // that because Cohen does not actually keep the numbers reduced modulo // the determinant, which leads to larger than necessary numbers. // This modifiaction was put in place in v3.9b. static void EuclUpdate(vec_ZZ& u, vec_ZZ& v, const ZZ& a, const ZZ& b, const ZZ& c, const ZZ& d, const ZZ& M) { long m = u.length(); long i; ZZ M1; RightShift(M1, M, 1); ZZ t1, t2, t3; for (i = 1; i <= m; i++) { mul(t1, u(i), a); mul(t2, v(i), b); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); t3 = t1; mul(t1, u(i), c); mul(t2, v(i), d); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); u(i) = t3; v(i) = t1; } } static void FixDiag(vec_ZZ& u, const ZZ& a, const vec_ZZ& v, const ZZ& M, long m) { long i; ZZ t1; for (i = 1; i <= m; i++) { mul(t1, a, v(i)); rem(u(i), t1, M); } } static void ReduceW(vec_ZZ& u, const ZZ& a, const vec_ZZ& v, const ZZ& M, long m) { long i; ZZ t1, t2; for (i = 1; i <= m; i++) { mul(t1, a, v(i)); sub(t2, u(i), t1); rem(u(i), t2, M); } } void HNF(mat_ZZ& W, const mat_ZZ& A_in, const ZZ& D_in) { mat_ZZ A = A_in; long n = A.NumRows(); long m = A.NumCols(); ZZ D = D_in; if (D < 0) negate(D, D); if (n == 0 || m == 0 || D == 0) LogicError("HNF: bad input"); W.SetDims(m, m); clear(W); long i, j, k; ZZ d, u, v, c1, c2; k = n; for (i = m; i >= 1; i--) { for (j = k-1; j >= 1; j--) { if (A(j, i) != 0) { XGCD(d, u, v, A(k, i), A(j, i)); div(c1, A(k, i), d); div(c2, A(j, i), d); negate(c2, c2); EuclUpdate(A(j), A(k), c1, c2, v, u, D); } } XGCD(d, u, v, A(k, i), D); FixDiag(W(i), u, A(k), D, i); if (W(i, i) == 0) W(i, i) = D; for (j = i+1; j <= m; j++) { div(c1, W(j, i), W(i, i)); ReduceW(W(j), c1, W(i), D, i); } div(D, D, d); k--; } } NTL_END_IMPL ntl-11.5.1/src/ctools.cpp0000644417616742025610000001052114064716022016752 0ustar gid-shoupvpug-gid-shoupv #include #include #include //============== define _ntl_GetWallTime() =============== // Some of the logic here, especially the Mac stuff, // is adapted from code obtained from here: /* * Author: David Robert Nadeau * Site: http://NadeauSoftware.com/ * License: Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/deed.en_US */ #if defined(NTL_HAVE_MACOS_TIME) // Mac OS // NOTE: new versions of Mac OS support clock_gettime. // However, we don't use it here as it might lead to inconsistencies // when binaries get compiled on a later OS and used on an earlier OS. #include #include static inline double InitTimeConvert() { mach_timebase_info_data_t timeBase; (void)mach_timebase_info( &timeBase ); return (double)timeBase.numer / (double)timeBase.denom / 1000000000.0; } double _ntl_GetWallTime( ) { static double timeConvert = InitTimeConvert(); // even in a multi-threaded environment, this will // be safely initialized, according to C++11 standard return double(mach_absolute_time()) * timeConvert; } #elif defined(NTL_HAVE_POSIX_TIME) // POSIX clock_gettime() #include #include #if defined(CLOCK_MONOTONIC) #define Clk_ID CLOCK_MONOTONIC #elif defined(CLOCK_REALTIME) #define Clk_ID CLOCK_REALTIME #elif defined(CLOCK_HIGHRES) #define Clk_ID CLOCK_HIGHRES #endif double _ntl_GetWallTime( ) { using namespace std; timespec ts; if (clock_gettime(Clk_ID, &ts)) return -1; else return double(ts.tv_sec) + double(ts.tv_nsec) / 1000000000.0; } #elif defined(NTL_HAVE_CHRONO_TIME) // C++11 // I have more faith in mach_absolute_time and clock_gettime // than this... #include double _ntl_GetWallTime( ) { auto current_time = std::chrono::steady_clock::now(); auto duration_in_seconds = std::chrono::duration(current_time.time_since_epoch()); return duration_in_seconds.count(); } #else // Fall back... // This will be the implementation on Windows... // and in this case, both GetTime() and GetWallTime() return // a "wall clock" time. double _ntl_GetTime(); double _ntl_GetWallTime( ) { return _ntl_GetTime(); } #endif //============== END define _ntl_GetWallTime() =============== /* * An IEEE double x is finite if and only if x - x == 0. * The function _ntl_IsFinite implements this logic; however, * it does not completely trust that an optimizing compiler * really implements this correctly, and so it goes out of its way to * confuse the compiler. For a good compiler that respects IEEE floating * point arithmetic, this may not be necessary, but it is better * to be a bit paranoid. * * Like the routine _ntl_ForceToMem below, this routine has the * side effect of forcing its argument into memory. * * I've checked the assembly code generated by various * versions of GCC, ICC, and MSVC++, and it all looks good. */ long _ntl_IsFinite(double *p) { volatile double x = *p; *p = x; double y = x; double diff = y - x; return diff == 0.0; } /* * On machines with wide floating point registers, the routine _ntl_ForceToMem * is used to force a floating point double to a memory location. * I've checked with GCC, and even with LTO, this will work. * That said, I wouln't really recommend applying LTO to NTL... */ void _ntl_ForceToMem(double *p) { volatile double x = *p; *p = x; } /* * The routine _ntl_ldexp(x, e) is like the standard ldexp(x, e) routine, * except that it takes a long exponent e, rather than an int exponenet. * Some care is taken to ensure reasonable overflow/undeflow behavior. * If the value of e does not fit into an int, then the result * is x*infinity or x*0, as appropriate. * Of course, this can only happen on platforms where long is wider * than int (e.g., most 64-bit platforms). * * We go out of our way to hide the fact that we are multiplying/dividing * by zero, so as to avoid unnecessary warnings, and to prevent * overly-agressive optimizing compilers from screwing things up. */ volatile double _ntl_ldexp_zero = 0.0; double _ntl_ldexp(double x, long e) { if (x == 0.0) return x; if (e > NTL_MAX_INT) return x/_ntl_ldexp_zero; else if (e < NTL_MIN_INT) return x*_ntl_ldexp_zero; else return std::ldexp(x, ((int) e)); } ntl-11.5.1/src/LLL.cpp0000644417616742025610000003141214064716022016074 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL static void ExactDiv(ZZ& qq, const ZZ& a, const ZZ& b) { NTL_ZZRegister(q); NTL_ZZRegister(r); DivRem(q, r, a, b); if (!IsZero(r)) { cerr << "a = " << a << "\n"; cerr << "b = " << b << "\n"; LogicError("ExactDiv: nonzero remainder"); } qq = q; } static void BalDiv(ZZ& q, const ZZ& a, const ZZ& d) // rounds a/d to nearest integer, breaking ties // by rounding towards zero. Assumes d > 0. { NTL_ZZRegister(r); DivRem(q, r, a, d); add(r, r, r); long cmp = compare(r, d); if (cmp > 0 || (cmp == 0 && q < 0)) add(q, q, 1); } static void MulAddDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, x, c1); mul(t2, y, c2); add(t1, t1, t2); ExactDiv(c, t1, z); } static void MulSubDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 - y*c2)/z { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, x, c1); mul(t2, y, c2); sub(t1, t1, t2); ExactDiv(c, t1, z); } #if 0 static void MulSubDiv(vec_ZZ& c, const vec_ZZ& c1, const vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { long n = c1.length(); if (c2.length() != n) LogicError("MulSubDiv: length mismatch"); c.SetLength(n); long i; for (i = 1; i <= n; i++) MulSubDiv(c(i), c1(i), c2(i), x, y, z); } #endif static void RowTransform(vec_ZZ& c1, vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v) // (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2) { long n = c1.length(); if (c2.length() != n) LogicError("MulSubDiv: length mismatch"); NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(t4); long i; for (i = 1; i <= n; i++) { mul(t1, x, c1(i)); mul(t2, y, c2(i)); add(t1, t1, t2); mul(t3, u, c1(i)); mul(t4, v, c2(i)); add(t3, t3, t4); c1(i) = t1; c2(i) = t3; } } static void RowTransform(ZZ& c1, ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v) // (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(t4); mul(t1, x, c1); mul(t2, y, c2); add(t1, t1, t2); mul(t3, u, c1); mul(t4, v, c2); add(t3, t3, t4); c1 = t1; c2 = t3; } static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, const ZZ& x) // c = c - x*c2 { long n = c.length(); if (c2.length() != n) LogicError("MulSubFrom: length mismatch"); long i; for (i = 1; i <= n; i++) MulSubFrom(c(i), c2(i), x); } static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, long x) // c = c - x*c2 { long n = c.length(); if (c2.length() != n) LogicError("MulSubFrom: length mismatch"); long i; for (i = 1; i <= n; i++) MulSubFrom(c(i), c2(i), x); } static long SwapTest(const ZZ& d0, const ZZ& d1, const ZZ& d2, const ZZ& lam, long a, long b) // test if a*d1^2 > b*(d0*d2 + lam^2) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); mul(t1, d0, d2); sqr(t2, lam); add(t1, t1, t2); mul(t1, t1, b); sqr(t2, d1); mul(t2, t2, a); return t2 > t1; } static void reduce(long k, long l, mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, mat_ZZ* U) { NTL_ZZRegister(t1); NTL_ZZRegister(r); if (P(l) == 0) return; add(t1, lam(k)(P(l)), lam(k)(P(l))); abs(t1, t1); if (t1 <= D[P(l)]) return; long j; long rr, small_r; BalDiv(r, lam(k)(P(l)), D[P(l)]); if (r.WideSinglePrecision()) { small_r = 1; rr = to_long(r); } else { small_r = 0; } if (small_r) { MulSubFrom(B(k), B(l), rr); if (U) MulSubFrom((*U)(k), (*U)(l), rr); for (j = 1; j <= l-1; j++) if (P(j) != 0) MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), rr); MulSubFrom(lam(k)(P(l)), D[P(l)], rr); } else { MulSubFrom(B(k), B(l), r); if (U) MulSubFrom((*U)(k), (*U)(l), r); for (j = 1; j <= l-1; j++) if (P(j) != 0) MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), r); MulSubFrom(lam(k)(P(l)), D[P(l)], r); } } static long swap(long k, mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, mat_ZZ* U, long m, long verbose) // swaps vectors k-1 and k; assumes P(k-1) != 0 // returns 1 if vector k-1 need to be reduced after the swap... // this only occurs in 'case 2' when there are linear dependencies { long i, j; NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); NTL_ZZRegister(e); NTL_ZZRegister(x); NTL_ZZRegister(y); if (P(k) != 0) { if (verbose) cerr << "swap case 1: " << k << "\n"; swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); for (i = k+1; i <= m; i++) { MulAddDiv(t1, lam(i)(P(k)-1), lam(i)(P(k)), lam(k)(P(k)-1), D[P(k)-2], D[P(k)-1]); MulSubDiv(t2, lam(i)(P(k)-1), lam(i)(P(k)), D[P(k)], lam(k)(P(k)-1), D[P(k)-1]); lam(i)(P(k)-1) = t1; lam(i)(P(k)) = t2; } MulAddDiv(D[P(k)-1], D[P(k)], lam(k)(P(k)-1), D[P(k)-2], lam(k)(P(k)-1), D[P(k)-1]); return 0; } else if (!IsZero(lam(k)(P(k-1)))) { if (verbose) cerr << "swap case 2: " << k << "\n"; XGCD(e, x, y, lam(k)(P(k-1)), D[P(k-1)]); ExactDiv(t1, lam(k)(P(k-1)), e); ExactDiv(t2, D[P(k-1)], e); t3 = t2; negate(t2, t2); RowTransform(B(k-1), B(k), t1, t2, y, x); if (U) RowTransform((*U)(k-1), (*U)(k), t1, t2, y, x); for (j = 1; j <= k-2; j++) if (P(j) != 0) RowTransform(lam(k-1)(P(j)), lam(k)(P(j)), t1, t2, y, x); sqr(t2, t2); ExactDiv(D[P(k-1)], D[P(k-1)], t2); for (i = k+1; i <= m; i++) if (P(i) != 0) { ExactDiv(D[P(i)], D[P(i)], t2); for (j = i+1; j <= m; j++) { ExactDiv(lam(j)(P(i)), lam(j)(P(i)), t2); } } for (i = k+1; i <= m; i++) { ExactDiv(lam(i)(P(k-1)), lam(i)(P(k-1)), t3); } swap(P(k-1), P(k)); return 1; } else { if (verbose) cerr << "swap case 3: " << k << "\n"; swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); swap(P(k-1), P(k)); return 0; } } static void IncrementalGS(mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, long& s, long k) { long n = B.NumCols(); long m = B.NumRows(); NTL_ZZRegister(u); NTL_ZZRegister(t1); NTL_ZZRegister(t2); long i, j; for (j = 1; j <= k-1; j++) { long posj = P(j); if (posj == 0) continue; InnerProduct(u, B(k), B(j)); for (i = 1; i <= posj-1; i++) { mul(t1, D[i], u); mul(t2, lam(k)(i), lam(j)(i)); sub(t1, t1, t2); div(t1, t1, D[i-1]); u = t1; } lam(k)(posj) = u; } InnerProduct(u, B(k), B(k)); for (i = 1; i <= s; i++) { mul(t1, D[i], u); mul(t2, lam(k)(i), lam(k)(i)); sub(t1, t1, t2); div(t1, t1, D[i-1]); u = t1; } if (u == 0) { P(k) = 0; } else { s++; P(k) = s; D[s] = u; } } static long LLL(vec_ZZ& D, mat_ZZ& B, mat_ZZ* U, long a, long b, long verbose) { long m = B.NumRows(); long n = B.NumCols(); long force_reduce = 1; vec_long P; P.SetLength(m); D.SetLength(m+1); D[0] = 1; vec_vec_ZZ lam; lam.SetLength(m); long j; for (j = 1; j <= m; j++) lam(j).SetLength(m); if (U) ident(*U, m); long s = 0; long k = 1; long max_k = 0; while (k <= m) { if (k > max_k) { IncrementalGS(B, P, D, lam, s, k); max_k = k; } if (k == 1) { force_reduce = 1; k++; continue; } if (force_reduce) for (j = k-1; j >= 1; j--) reduce(k, j, B, P, D, lam, U); if (P(k-1) != 0 && (P(k) == 0 || SwapTest(D[P(k)], D[P(k)-1], D[P(k)-2], lam(k)(P(k)-1), a, b))) { force_reduce = swap(k, B, P, D, lam, U, max_k, verbose); k--; } else { force_reduce = 1; k++; } } D.SetLength(s+1); return s; } static long image(ZZ& det, mat_ZZ& B, mat_ZZ* U, long verbose) { long m = B.NumRows(); long n = B.NumCols(); long force_reduce = 1; vec_long P; P.SetLength(m); vec_ZZ D; D.SetLength(m+1); D[0] = 1; vec_vec_ZZ lam; lam.SetLength(m); long j; for (j = 1; j <= m; j++) lam(j).SetLength(m); if (U) ident(*U, m); long s = 0; long k = 1; long max_k = 0; while (k <= m) { if (k > max_k) { IncrementalGS(B, P, D, lam, s, k); max_k = k; } if (k == 1) { force_reduce = 1; k++; continue; } if (force_reduce) for (j = k-1; j >= 1; j--) reduce(k, j, B, P, D, lam, U); if (P(k-1) != 0 && P(k) == 0) { force_reduce = swap(k, B, P, D, lam, U, max_k, verbose); k--; } else { force_reduce = 1; k++; } } det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose) { vec_ZZ D; long s; s = LLL(D, B, &U, 3, 4, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, long verbose) { vec_ZZ D; long s; s = LLL(D, B, 0, 3, 4, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) LogicError("LLL: bad args"); vec_ZZ D; long s; s = LLL(D, B, &U, a, b, verbose); det = D[s]; return s; } long LLL(ZZ& det, mat_ZZ& B, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) LogicError("LLL: bad args"); vec_ZZ D; long s; s = LLL(D, B, 0, a, b, verbose); det = D[s]; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long verbose) { vec_ZZ D; long s; s = LLL(D, B, &U, 3, 4, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long verbose) { vec_ZZ D; long s; s = LLL(D, B, 0, 3, 4, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) LogicError("LLL_plus: bad args"); vec_ZZ D; long s; s = LLL(D, B, &U, a, b, verbose); D_out = D; return s; } long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long a, long b, long verbose) { if (a <= 0 || b <= 0 || a > b || b/4 >= a) LogicError("LLL_plus: bad args"); vec_ZZ D; long s; s = LLL(D, B, 0, a, b, verbose); D_out = D; return s; } long image(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose) { return image(det, B, &U, verbose); } long image(ZZ& det, mat_ZZ& B, long verbose) { return image(det, B, 0, verbose); } long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce) { long n = A.NumRows(); long m = A.NumCols(); if (y.length() != m) LogicError("LatticeSolve: dimension mismatch"); if (reduce < 0 || reduce > 2) LogicError("LatticeSolve: bad reduce parameter"); if (IsZero(y)) { x.SetLength(n); clear(x); return 1; } mat_ZZ A1, U1; ZZ det2; long im_rank, ker_rank; A1 = A; im_rank = image(det2, A1, U1); ker_rank = n - im_rank; mat_ZZ A2, U2; long new_rank; long i; A2.SetDims(im_rank + 1, m); for (i = 1; i <= im_rank; i++) A2(i) = A1(ker_rank + i); A2(im_rank + 1) = y; new_rank = image(det2, A2, U2); if (new_rank != im_rank || (U2(1)(im_rank+1) != 1 && U2(1)(im_rank+1) != -1)) return 0; vec_ZZ x1; x1.SetLength(im_rank); for (i = 1; i <= im_rank; i++) x1(i) = U2(1)(i); if (U2(1)(im_rank+1) == 1) negate(x1, x1); vec_ZZ x2, tmp; x2.SetLength(n); clear(x2); tmp.SetLength(n); for (i = 1; i <= im_rank; i++) { mul(tmp, U1(ker_rank+i), x1(i)); add(x2, x2, tmp); } if (reduce == 0) { x = x2; return 1; } else if (reduce == 1) { U1.SetDims(ker_rank+1, n); U1(ker_rank+1) = x2; image(det2, U1); x = U1(ker_rank + 1); return 1; } else if (reduce == 2) { U1.SetDims(ker_rank, n); LLL(det2, U1); U1.SetDims(ker_rank+1, n); U1(ker_rank+1) = x2; image(det2, U1); x = U1(ker_rank + 1); return 1; } return 0; } NTL_END_IMPL ntl-11.5.1/src/LLL_FP.cpp0000644417616742025610000010660514064716022016470 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) ResourceError("LLL_FP: numbers too big...use LLL_XD"); } static double InnerProduct(double *a, double *b, long n) { double s; long i; s = 0; for (i = 1; i <= n; i++) s += a[i]*b[i]; return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(double *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i]); if (t > res) res = t; } return res; } static void RowTransformStart(double *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i] < TR_BND && a[i] > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, double *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, double *a, double *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; conv(mu, MU1); CheckFinite(&mu); long n = A.length(); long i; if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i] -= b[i]; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i] += b[i]; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i] -= mu*b[i]; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] -= b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] += b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < b_bnd && b[i] > -b_bnd) { a[i] -= b[i]*mu; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, double **B1, double **mu, double *b, double *c, long k, double bound, long st, double *buf) { long n = B.NumCols(); long i, j; double s, t1, y, t; ZZ T1; long test; double *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { s = InnerProduct(B1[k], B1[j], n); // test = b[k]*b[j] >= NTL_FDOUBLE_PRECISION^2 test = (b[k]/NTL_FDOUBLE_PRECISION >= NTL_FDOUBLE_PRECISION/b[j]); // test = test && s^2 <= b[k]*b[j]/bound, // but we compute it in a strange way to avoid overflow if (test && (y = fabs(s)) != 0) { t = y/b[j]; t1 = b[k]/y; if (t <= 1) test = (t*bound <= t1); else if (t1 >= 1) test = (t <= t1/bound); else test = 0; } if (test) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } double *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) { t1 += mu_j[i]*buf[i]; } mu_k[j] = (buf[j] = (s - t1))/c[j]; } #if (!NTL_EXT_DOUBLE) // Kahan summation double c1; s = c1 = 0; for (j = 1; j <= k-1; j++) { y = mu_k[j]*buf[j] - c1; t = s+y; c1 = t-s; c1 = c1-y; s = t; } #else s = 0; for (j = 1; j <= k-1; j++) s += mu_k[j]*buf[j]; #endif c[k] = b[k] - s; } NTL_CHEAP_THREAD_LOCAL double LLLStatusInterval = 900.0; NTL_CHEAP_THREAD_LOCAL char *LLLDumpFile = 0; static NTL_CHEAP_THREAD_LOCAL double red_fudge = 0; static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double RR_GS_time = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "LLL_FP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("LLL_FP: too much loss of precision...stop!"); } #if 0 static void print_mus(double **mu, long k) { long i; for (i = k-1; i >= 1; i--) cerr << mu[k][i] << " "; cerr << "\n"; } #endif void ComputeGS(const mat_ZZ& B, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long k, const RR& bound, long st, vec_RR& buf, const RR& bound2); static void RR_GS(mat_ZZ& B, double **B1, double **mu, double *b, double *c, double *buf, long prec, long rr_st, long k, long m_orig, mat_RR& rr_B1, mat_RR& rr_mu, vec_RR& rr_b, vec_RR& rr_c) { double tt; cerr << "LLL_FP: RR refresh " << rr_st << "..." << k << "..."; tt = GetTime(); if (rr_st > k) ResourceError("LLL_FP: can not continue!!!"); RRPush push; RR::SetPrecision(prec); long n = B.NumCols(); rr_B1.SetDims(k, n); rr_mu.SetDims(k, m_orig); rr_b.SetLength(k); rr_c.SetLength(k); vec_RR rr_buf; rr_buf.SetLength(k); long i, j; for (i = rr_st; i <= k; i++) for (j = 1; j <= n; j++) conv(rr_B1(i, j), B(i, j)); for (i = rr_st; i <= k; i++) InnerProduct(rr_b(i), rr_B1(i), rr_B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = rr_st; i <= k; i++) ComputeGS(B, rr_B1, rr_mu, rr_b, rr_c, i, bound, 1, rr_buf, bound2); for (i = rr_st; i <= k; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], rr_B1(i,j)); CheckFinite(&B1[i][j]); } for (i = rr_st; i <= k; i++) for (j = 1; j <= i-1; j++) { conv(mu[i][j], rr_mu(i,j)); } for (i = rr_st; i <= k; i++) { conv(b[i], rr_b(i)); CheckFinite(&b[i]); } for (i = rr_st; i <= k; i++) { conv(c[i], rr_c(i)); CheckFinite(&c[i]); } for (i = 1; i <= k-1; i++) { conv(buf[i], rr_buf[i]); } tt = GetTime()-tt; RR_GS_time += tt; cerr << tt << " (" << RR_GS_time << ")\n"; } void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c) { long n = B.NumCols(); long k = B.NumRows(); mat_RR B1; vec_RR b; B1.SetDims(k, n); mu.SetDims(k, k); b.SetLength(k); c.SetLength(k); vec_RR buf; buf.SetLength(k); long i, j; for (i = 1; i <= k; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= k; i++) InnerProduct(b(i), B1(i), B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = 1; i <= k; i++) ComputeGS(B, B1, mu, b, c, i, bound, 1, buf, bound2); } static long ll_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check, double **B1, double **mu, double *b, double *c, long m, long init_k, long &quit) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; double mu1; double t1; ZZ T1; double *tp; static double bound = 0; if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*NTL_DOUBLE_PRECISION); i > 0; i--) bound = bound * 2; } double half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; UniqueArray buf_store; buf_store.SetLength(m+1); double *buf = buf_store.get(); vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); UniqueArray max_b_store; max_b_store.SetLength(m+1); double *max_b = max_b_store.get(); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long rst; long counter; long start_over; long trigger_index; long small_trigger; long cnt; mat_RR rr_B1; mat_RR rr_mu; vec_RR rr_c; vec_RR rr_b; long m_orig = m; long rr_st = 1; long max_k = 0; long prec = RR::precision(); double tt; long swap_cnt = 0; while (k <= m) { if (k > max_k) { max_k = k; swap_cnt = 0; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (k < rr_st) rr_st = k; if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); CheckFinite(&c[k]); st[k] = k; if (swap_cnt > 200000) { cerr << "LLL_FP: swap loop?\n"; RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); if (rr_st < st[k+1]) st[k+1] = rr_st; rr_st = k+1; rst = k; swap_cnt = 0; } counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; long thresh = 10; long sz=0, new_sz; long did_rr_gs = 0; do { // size reduction counter++; if ((counter & 127) == 0) { new_sz = 0; for (j = 1; j <= n; j++) new_sz += NumBits(B(k,j)); if ((counter >> 7) == 1 || new_sz < sz) { sz = new_sz; } else { cerr << "LLL_FP: warning--infinite loop?\n"; } } Fc1 = 0; start_over = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > thresh) { if (log_red <= 15) { while (log_red > 10) inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; if (!did_rr_gs) { RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); if (rr_st < st[k+1]) st[k+1] = rr_st; rr_st = k+1; did_rr_gs = 1; rst = k; trigger_index = k; small_trigger = 0; start_over = 1; break; } } else { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; if (k < rr_st) rr_st = k; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-0.5); else mu1 = floor(mu1+0.5); double *mu_k = mu[k]; double *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); if (!did_rr_gs) { b[k] = InnerProduct(B1[k], B1[k], n); CheckFinite(&b[k]); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); CheckFinite(&c[k]); } else { RR_GS(B, B1, mu, b, c, buf, prec, rr_st, k, m_orig, rr_B1, rr_mu, rr_b, rr_c); rr_st = k+1; } rst = k; } } while (Fc1 || start_over); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; t1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; if (k < rr_st) rr_st = k; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions double cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; t1 = max_b[i]; max_b[i] = max_b[i-1]; max_b[i-1] = t1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; NumSwaps++; swap_cnt++; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; t1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; swap_cnt++; // cout << "-\n"; } else { k++; // cout << "+\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } return m; } static long LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; ZZ MU; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); double **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, m+1); double **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+1); double *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+1); double *b = b_store.get(); // squared lengths of basis vectors for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } new_m = ll_LLL_FP(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long LLL_FP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_FP: bad delta"); if (deep < 0) LogicError("LLL_FP: bad deep"); return LLL_FP(B, 0, delta, deep, check); } long LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_FP: bad delta"); if (deep < 0) LogicError("LLL_FP: bad deep"); return LLL_FP(B, &U, delta, deep, check); } static vec_double BKZConstant; static void ComputeBKZConstant(long beta, long p) { const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } static vec_double BKZThresh; static void ComputeBKZThresh(double *c, long beta) { BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = exp(x/double(i))*BKZConstant(i); if (!IsFinite(&BKZThresh(i))) BKZThresh(i) = 0; } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_FP(mat_ZZ& BB, mat_ZZ* UU, double delta, long beta, long prune, LLLCheckFct check) { long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; double t1; ZZ T1; double *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); double **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, m+1); double **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+2); double *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+2); double *b = b_store.get(); // squared lengths of basis vectors double cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); double *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); double *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); double *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); double *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); double *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get();; mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) t1 += utildavec[i]*mu[i][t]; yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta - 8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("BKZ_FP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) LogicError("BKZ_FP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) LogicError("BKZ_FP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_FP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) LogicError("BKZ_FP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_FP: internal error"); if (quit) break; } } z = 0; } else { // LLL_FP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_FP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_FP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_FP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_FP: bad delta"); if (beta < 2) LogicError("BKZ_FP: bad block size"); return BKZ_FP(BB, &UU, delta, beta, prune, check); } long BKZ_FP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; RR_GS_time = 0; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_FP: bad delta"); if (beta < 2) LogicError("BKZ_FP: bad block size"); return BKZ_FP(BB, 0, delta, beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/LLL_QP.cpp0000644417616742025610000012644614064716022016510 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) ResourceError("LLL_QP: numbers too big...use LLL_XD"); } static inline void CheckFinite(quad_float *p) { if (!IsFinite(p)) ResourceError("LLL_QP: numbers too big...use LLL_XD"); } static quad_float InnerProduct(quad_float *a, quad_float *b, long n) { quad_float s; long i; s = 0; for (i = 1; i <= n; i++) s += a[i]*b[i]; return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(quad_float *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i].hi); if (t > res) res = t; } return res; } static void RowTransformStart(quad_float *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i].hi < TR_BND && a[i].hi > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, quad_float *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, quad_float *a, quad_float *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; long n = A.length(); long i; conv(mu, MU1); CheckFinite(&mu); if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i].hi -= b[i].hi; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i].hi += b[i].hi; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i].hi -= mu*b[i].hi; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi -= b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi += b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < b_bnd && b[i].hi > -b_bnd) { a[i].hi -= b[i].hi*mu; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, quad_float **B1, quad_float **mu, quad_float *b, quad_float *c, long k, double bound, long st, quad_float *buf) { long n = B.NumCols(); long i, j; quad_float s, t1, y, t; ZZ T1; long test; quad_float *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { if (b[k].hi/NTL_FDOUBLE_PRECISION < NTL_FDOUBLE_PRECISION/b[j].hi) { // we can compute inner product exactly in double precision double z = 0; quad_float *B1_k = B1[k]; quad_float *B1_j = B1[j]; for (i = 1; i <= n; i++) z += B1_k[i].hi * B1_j[i].hi; s = z; } else { s = InnerProduct(B1[k], B1[j], n); y = fabs(s); if (y.hi == 0) test = (b[k].hi != 0); else { double t = y.hi/b[j].hi; double t1 = b[k].hi/y.hi; if (t <= 1) test = (t*bound <= t1); else if (t1 >= 1) test = (t <= t1/bound); else test = 0; } if (test) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } } quad_float *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) t1 += mu_j[i]*buf[i]; mu_k[j] = (buf[j] = (s - t1))/c[j]; } s = 0; for (j = 1; j <= k-1; j++) s += mu_k[j]*buf[j]; c[k] = b[k] - s; } NTL_TLS_GLOBAL_DECL_INIT(quad_float, red_fudge, (to_quad_float(0))) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); long i; // initial log_red should be <= NTL_DOUBLE_PRECISION-2, // to help ensure stability in BKZ_QP1 log_red = NTL_DOUBLE_PRECISION-2; red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); red_fudge = red_fudge * 2; log_red--; cerr << "LLL_QP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("LLL_QP: too much loss of precision...stop!"); } static long ll_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check, quad_float **B1, quad_float **mu, quad_float *b, quad_float *c, long m, long init_k, long &quit) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; quad_float mu1; quad_float t1; double dt1; ZZ T1; quad_float *tp; static NTL_CHEAP_THREAD_LOCAL double bound = 0; if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*2*NTL_DOUBLE_PRECISION); i > 0; i--) { bound = bound * 2; } } quad_float half = to_quad_float(0.5); quad_float half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; UniqueArray buf_store; buf_store.SetLength(m+1); quad_float *buf = buf_store.get(); vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); UniqueArray max_b_store; max_b_store.SetLength(m+1); double *max_b = max_b_store.get(); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long rst; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); CheckFinite(&c[k]); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_QP: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); quad_float *mu_k = mu[k]; quad_float *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } // cout << j << " " << mu[k][j] << " " << mu1 << "\n"; mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); b[k] = InnerProduct(B1[k], B1[k], n); CheckFinite(&b[k]); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); CheckFinite(&c[k]); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; dt1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = dt1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions quad_float cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; dt1 = max_b[i]; max_b[i] = max_b[i-1]; max_b[i-1] = dt1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; NumSwaps++; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; dt1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = dt1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { k++; // cout << "+ " << k << "\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } return m; } static long LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; quad_float s; ZZ MU; quad_float mu1; quad_float t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, m+1); quad_float **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+1); quad_float *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+1); quad_float *b = b_store.get(); // squared lengths of basis vectors for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } new_m = ll_LLL_QP(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long LLL_QP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_QP: bad delta"); if (deep < 0) LogicError("LLL_QP: bad deep"); return LLL_QP(B, 0, to_quad_float(delta), deep, check); } long LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_QP: bad delta"); if (deep < 0) LogicError("LLL_QP: bad deep"); return LLL_QP(B, &U, to_quad_float(delta), deep, check); } NTL_TLS_GLOBAL_DECL(vec_quad_float, BKZConstant) static void ComputeBKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); const quad_float c_PI = to_quad_float("3.141592653589793238462643383279502884197"); const quad_float LogPI = to_quad_float("1.144729885849400174143427351353058711647"); BKZConstant.SetLength(beta-1); vec_quad_float Log; Log.SetLength(beta); long i, j, k; quad_float x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_quad_float(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/to_quad_float(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/to_quad_float(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/to_quad_float(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_quad_float, BKZThresh) static void ComputeBKZThresh(quad_float *c, long beta) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); NTL_TLS_GLOBAL_ACCESS(BKZThresh); BKZThresh.SetLength(beta-1); long i; quad_float x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = exp(x/to_quad_float(i))*BKZConstant(i); if (!IsFinite(&BKZThresh(i))) BKZThresh(i) = 0; } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_QP(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; quad_float t1; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, m+1); quad_float **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+2); quad_float *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+2); quad_float *b = b_store.get(); // squared lengths of basis vectors quad_float cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); quad_float *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); quad_float *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); quad_float *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); quad_float *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); quad_float *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get();; mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; quad_float eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) LogicError("BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_QP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) LogicError("BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_QP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_QP: bad delta"); if (beta < 2) LogicError("BKZ_QP: bad block size"); return BKZ_QP(BB, &UU, to_quad_float(delta), beta, prune, check); } long BKZ_QP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_QP: bad delta"); if (beta < 2) LogicError("BKZ_QP: bad block size"); return BKZ_QP(BB, 0, to_quad_float(delta), beta, prune, check); } static long BKZ_QP1(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, m+1); quad_float **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+2); quad_float *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+2); quad_float *b = b_store.get(); // squared lengths of basis vectors double cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); double *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); double *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); double *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); double *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); double *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get();; mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); CheckFinite(&b[i]); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = to_double(c[jj]); utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*to_double(c[t]); ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = to_double(BKZThresh(t-jj)); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { double t1; t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*to_double(mu[i][t]); } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); quad_float t1; if ((delta-8*red_fudge)*c[jj] > cbar*(1+64/NTL_FDOUBLE_PRECISION)) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } b[jj] = InnerProduct(B1[jj], B1[jj], n); CheckFinite(&b[jj]); if (b[jj] == 0) LogicError("BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_QP(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) LogicError("BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_QP(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_QP1(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_QP: bad delta"); if (beta < 2) LogicError("BKZ_QP: bad block size"); return BKZ_QP1(BB, &UU, to_quad_float(delta), beta, prune, check); } long BKZ_QP1(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_QP: bad delta"); if (beta < 2) LogicError("BKZ_QP: bad block size"); return BKZ_QP1(BB, 0, to_quad_float(delta), beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/LLL_RR.cpp0000644417616742025610000006646114064716022016513 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } void ComputeGS(const mat_ZZ& B, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long k, const RR& bound, long st, vec_RR& buf, const RR& bound2) { long i, j; RR s, t, t1; ZZ T1; if (st < k) { for (i = 1; i < st; i++) mul(buf(i), mu(k,i), c(i)); } for (j = st; j <= k-1; j++) { InnerProduct(s, B1(k), B1(j)); sqr(t1, s); mul(t1, t1, bound); mul(t, b(k), b(j)); if (t >= bound2 && t >= t1) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } clear(t1); for (i = 1; i <= j-1; i++) { mul(t, mu(j, i), buf(i)); add(t1, t1, t); } sub(t, s, t1); buf(j) = t; div(mu(k, j), t, c(j)); } clear(s); for (j = 1; j <= k-1; j++) { mul(t, mu(k, j), buf(j)); add(s, s, t); } sub(c(k), b(k), s); } NTL_TLS_GLOBAL_DECL(RR, red_fudge) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); log_red = long(0.50*RR::precision()); power2(red_fudge, -log_red); } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); mul(red_fudge, red_fudge, 2); log_red--; cerr << "LLL_RR: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("LLL_RR: can not continue...sorry"); } static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check, mat_RR& B1, mat_RR& mu, vec_RR& b, vec_RR& c, long m, long init_k, long &quit) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; RR mu1, t1, t2, cc; ZZ T1; RR bound; // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; vec_RR buf; buf.SetLength(m); long rst; long counter; long trigger_index; long small_trigger; long cnt; RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf, bound2); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { abs(t1, mu(k,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(k,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(k,i), mu(k,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(k,i), mu(k,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(k,i), mu(k,i), t2); } } conv(MU, mu1); sub(mu(k,j), mu(k,j), mu1); RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(k, i), B(k, i)); InnerProduct(b(k), B1(k), B1(k)); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf, bound2); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(b(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); swap(B1(i), B1(i+1)); swap(b(i), b(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions cc = b(k); long l = 1; while (l <= k-1) { mul(t1, delta, c(l)); if (t1 > cc) break; sqr(t1, mu(k,l)); mul(t1, t1, c(l)); sub(cc, cc, t1); l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); swap(B1(i), B1(i-1)); swap(mu(i), mu(i-1)); swap(b(i), b(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } k = l; continue; } } // end deep insertions // test LLL reduction condition if (k <= 1) { k++; } else { sqr(t1, mu(k,k-1)); mul(t1, t1, c(k-1)); add(t1, t1, c(k)); mul(t2, delta, c(k-1)); if (t2 > t1) { // swap rows k, k-1 swap(B(k), B(k-1)); swap(B1(k), B1(k-1)); swap(mu(k), mu(k-1)); swap(b(k), b(k-1)); if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; } else { k++; } } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } return m; } static long LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; RR s; ZZ MU; RR mu1; RR t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); mat_RR B1; // approximates B B1.SetDims(m, n); mat_RR mu; mu.SetDims(m, m); vec_RR c; // squared lengths of Gramm-Schmidt basis vectors c.SetLength(m); vec_RR b; // squared lengths of basis vectors b.SetLength(m); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= m; i++) { InnerProduct(b(i), B1(i), B1(i)); } new_m = ll_LLL_RR(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long LLL_RR(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_RR: bad delta"); if (deep < 0) LogicError("LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return LLL_RR(B, 0, Delta, deep, check); } long LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_RR: bad delta"); if (deep < 0) LogicError("LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return LLL_RR(B, &U, Delta, deep, check); } NTL_TLS_GLOBAL_DECL(vec_RR, BKZConstant) static void ComputeBKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); RR c_PI; ComputePi(c_PI); RR LogPI = log(c_PI); BKZConstant.SetLength(beta-1); vec_RR Log; Log.SetLength(beta); long i, j, k; RR x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_RR(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x += Log(j); x = exp(x/k); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x += Log(j); x += 0.5*LogPI - 2*(k+1)*Log(2); x = exp(2*x/i); } // Second, we compute y = 2^{2*p/i} y = exp(-(2*p/to_RR(i))*Log(2)); BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_RR, BKZThresh) static void ComputeBKZThresh(RR *c, long beta) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); NTL_TLS_GLOBAL_ACCESS(BKZThresh); BKZThresh.SetLength(beta-1); long i; RR x; RR t1; x = 0; for (i = 1; i <= beta-1; i++) { log(t1, c[i-1]); add(x, x, t1); div(t1, x, i); exp(t1, t1); mul(BKZThresh(i), t1, BKZConstant(i)); } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_RR(mat_ZZ& BB, mat_ZZ* UU, const RR& delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; RR t1, t2; ZZ T1; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); mat_RR B1; B1.SetDims(m+1, n); mat_RR mu; mu.SetDims(m+1, m); vec_RR c; c.SetLength(m+1); vec_RR b; b.SetLength(m+1); RR cbar; vec_RR ctilda; ctilda.SetLength(m+1); vec_RR vvec; vvec.SetLength(m+1); vec_RR yvec; yvec.SetLength(m+1); vec_RR uvec; uvec.SetLength(m+1); vec_RR utildavec; utildavec.SetLength(m+1); vec_long Deltavec; Deltavec.SetLength(m+1); vec_long deltavec; deltavec.SetLength(m+1); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= m; i++) { InnerProduct(b(i), B1(i), B1(i)); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c(jj), kk-jj+1); cbar = c(jj); conv(utildavec(jj), 1); conv(uvec(jj), 1); conv(yvec(jj), 0); conv(vvec(jj), 0); Deltavec(jj) = 0; s = t = jj; deltavec(jj) = 1; for (i = jj+1; i <= kk+1; i++) { conv(ctilda(i), 0); conv(uvec(i), 0); conv(utildavec(i), 0); conv(yvec(i), 0); Deltavec(i) = 0; conv(vvec(i), 0); deltavec(i) = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } add(t1, yvec(t), utildavec(t)); sqr(t1, t1); mul(t1, t1, c(t)); add(ctilda(t), ctilda(t+1), t1); if (prune > 0 && t > jj) sub(t1, cbar, BKZThresh(t-jj)); else t1 = cbar; if (ctilda(t) jj) { t--; clear(t1); for (i = t+1; i <= s; i++) { mul(t2, utildavec(i), mu(i,t)); add(t1, t1, t2); } yvec(t) = t1; negate(t1, t1); if (sign(t1) >= 0) { sub(t1, t1, 0.5); ceil(t1, t1); } else { add(t1, t1, 0.5); floor(t1, t1); } utildavec(t) = t1; vvec(t) = t1; Deltavec(t) = 0; negate(t1, t1); if (t1 < yvec(t)) deltavec(t) = -1; else deltavec(t) = 1; } else { cbar = ctilda(jj); for (i = jj; i <= kk; i++) { uvec(i) = utildavec(i); } } } else { t++; s = max(s, t); if (t < s) Deltavec(t) = -Deltavec(t); if (Deltavec(t)*deltavec(t) >= 0) Deltavec(t) += deltavec(t); add(utildavec(t), vvec(t), Deltavec(t)); } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); mul(t1, red_fudge, -8); add(t1, t1, delta); mul(t1, t1, c(jj)); if (t1 > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec(i) != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("BKZ_RR: internal error"); if (s > 0) { // special case // cerr << "special case\n"; NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) LogicError("BKZ_RR: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec(i) == 0) continue; conv(MU, uvec(i)); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } for (i = 1; i <= n; i++) conv(B1(jj, i), B(jj, i)); InnerProduct(b(jj), B1(jj), B1(jj)); if (b(jj) == 0) LogicError("BKZ_RR: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_RR(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) LogicError("BKZ_RR: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); swap(b(i-1), b(i)); if (U) swap((*U)(i-1), (*U)(i)); } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_RR: internal error"); if (quit) break; } } z = 0; } else { // LLL_RR // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_RR(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_RR: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_RR(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_RR: bad delta"); if (beta < 2) LogicError("BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return BKZ_RR(BB, &UU, Delta, beta, prune, check); } long BKZ_RR(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_RR: bad delta"); if (beta < 2) LogicError("BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return BKZ_RR(BB, 0, Delta, beta, prune, check); } void NearVector(vec_ZZ& ww, const mat_ZZ& BB, const vec_ZZ& a) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = BB.NumCols(); if (n != BB.NumRows()) LogicError("NearVector: matrix must be square"); if (n != a.length()) LogicError("NearVector: dimension mismatch"); long i, j; mat_ZZ B; B.SetDims(n+1, n); for (i = 1; i <= n; i++) B(i) = BB(i); B(n+1) = a; mat_RR B1, mu; vec_RR b, c; B1.SetDims(n+1, n); mu.SetDims(n+1, n+1); b.SetLength(n+1); c.SetLength(n+1); vec_RR buf; buf.SetLength(n+1); for (i = 1; i <= n+1; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); for (i = 1; i <= n+1; i++) InnerProduct(b(i), B1(i), B1(i)); RR bound; power2(bound, 2*long(0.15*RR::precision())); RR bound2; power2(bound2, 2*RR::precision()); for (i = 1; i <= n+1; i++) ComputeGS(B, B1, mu, b, c, i, bound, 1, buf, bound2); init_red_fudge(); RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); RR t1, t2, mu1; ZZ MU; long trigger_index = n+1; long small_trigger = 0; long cnt = 0; long Fc1; vec_ZZ w; w.SetLength(n); clear(w); do { Fc1 = 0; for (j = n; j >= 1; j--) { abs(t1, mu(n+1,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(n+1,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(n+1,i), mu(n+1,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(n+1,i), mu(n+1,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(n+1,i), mu(n+1,i), t2); } } conv(MU, mu1); sub(mu(n+1,j), mu(n+1,j), mu1); RowTransform(B(n+1), B(j), MU); RowTransform2(w, B(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(n+1, i), B(n+1, i)); InnerProduct(b(n+1), B1(n+1), B1(n+1)); ComputeGS(B, B1, mu, b, c, n+1, bound, 1, buf, bound2); } } while (Fc1); ww = w; } NTL_END_IMPL ntl-11.5.1/src/LLL_XD.cpp0000644417616742025610000006367414064716022016506 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_START_IMPL static xdouble InnerProduct(xdouble *a, xdouble *b, long n) { xdouble s; long i; s = 0; for (i = 1; i <= n; i++) MulAdd(s, s, a[i], b[i]); return s; } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } static void ComputeGS(mat_ZZ& B, xdouble **B1, xdouble **mu, xdouble *b, xdouble *c, long k, xdouble bound, long st, xdouble *buf) { long n = B.NumCols(); long i, j; xdouble s, t1, y, t; ZZ T1; xdouble *mu_k = mu[k]; if (st < k) { for (i = 1; i < st; i++) buf[i] = mu_k[i]*c[i]; } for (j = st; j <= k-1; j++) { if (b[k]*b[j] < NTL_FDOUBLE_PRECISION*NTL_FDOUBLE_PRECISION) { double z = 0; xdouble *B1_k = B1[k]; xdouble *B1_j = B1[j]; for (i = 1; i <= n; i++) z += B1_k[i].x * B1_j[i].x; s = z; } else { s = InnerProduct(B1[k], B1[j], n); if (s*s <= b[k]*b[j]/bound) { InnerProduct(T1, B(k), B(j)); conv(s, T1); } } xdouble *mu_j = mu[j]; t1 = 0; for (i = 1; i <= j-1; i++) MulAdd(t1, t1, mu_j[i], buf[i]); mu_k[j] = (buf[j] = (s - t1))/c[j]; } s = 0; for (j = 1; j <= k-1; j++) MulAdd(s, s, mu_k[j], buf[j]); c[k] = b[k] - s; } NTL_TLS_GLOBAL_DECL_INIT(xdouble, red_fudge, (to_xdouble(0))) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); red_fudge = red_fudge * 2; log_red--; cerr << "LLL_XD: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("LLL_XD: can not continue...sorry"); } static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- LLL_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check, xdouble **B1, xdouble **mu, xdouble *b, xdouble *c, long m, long init_k, long &quit) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; xdouble *tp; NTL_TLS_LOCAL_INIT(xdouble, bound, (to_xdouble(0))); if (bound == 0) { // we tolerate a 15% loss of precision in computing // inner products in ComputeGS. bound = 1; for (i = 2*long(0.15*NTL_DOUBLE_PRECISION); i > 0; i--) { bound = bound * 2; } } xdouble half = to_xdouble(0.5); xdouble half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long st_mem; st_mem.SetLength(m+2); long *st = st_mem.elts(); for (i = 1; i < k; i++) st[i] = i; for (i = k; i <= m+1; i++) st[i] = 1; UniqueArray buf_store; buf_store.SetLength(m+1); xdouble *buf = buf_store.get(); long rst; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) LLLStatus(max_k, tt, m, B); } if (st[k] == k) rst = 1; else rst = k; if (st[k] < st[k+1]) st[k+1] = st[k]; ComputeGS(B, B1, mu, b, c, k, bound, st[k], buf); st[k] = k; counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = rst-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); xdouble *mu_k = mu[k]; xdouble *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) MulSub(mu_k[i], mu_k[i], mu1, mu_j[i]); } mu_k[j] -= mu1; conv(MU, mu1); // cout << j << " " << MU << "\n"; RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1[k][i], B(k, i)); b[k] = InnerProduct(B1[k], B1[k], n); ComputeGS(B, B1, mu, b, c, k, bound, 1, buf); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (b[k] == 0) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = b[i]; b[i] = b[i+1]; b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } for (i = k; i <= m+1; i++) st[i] = 1; m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions xdouble cc = b[k]; long l = 1; while (l <= k-1 && delta*c[l] <= cc) { cc = cc - mu[k][l]*mu[k][l]*c[l]; l++; } if (l <= k-1 && (l <= deep || k-l <= deep)) { // deep insertion at position l for (i = k; i > l; i--) { // swap rows i, i-1 swap(B(i), B(i-1)); tp = B1[i]; B1[i] = B1[i-1]; B1[i-1] = tp; tp = mu[i]; mu[i] = mu[i-1]; mu[i-1] = tp; t1 = b[i]; b[i] = b[i-1]; b[i-1] = t1; if (U) swap((*U)(i), (*U)(i-1)); } k = l; continue; } } // end deep insertions // test LLL reduction condition if (k > 1 && delta*c[k-1] > c[k] + mu[k][k-1]*mu[k][k-1]*c[k-1]) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; tp = mu[k]; mu[k] = mu[k-1]; mu[k-1] = tp; t1 = b[k]; b[k] = b[k-1]; b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { k++; // cout << "+ " << k << "\n"; } } if (verbose) { LLLStatus(m+1, GetTime(), m, B); } return m; } static long LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; xdouble s; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); xdouble **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, m+1); xdouble **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+1); xdouble *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+1); xdouble *b = b_store.get(); // squared lengths of basis vectors for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); } new_m = ll_LLL_XD(B, U, delta, deep, check, B1, mu, b, c, m, 1, quit); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long LLL_XD(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_XD: bad delta"); if (deep < 0) LogicError("LLL_XD: bad deep"); return LLL_XD(B, 0, to_xdouble(delta), deep, check); } long LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("LLL_XD: bad delta"); if (deep < 0) LogicError("LLL_XD: bad deep"); return LLL_XD(B, &U, to_xdouble(delta), deep, check); } NTL_TLS_GLOBAL_DECL(vec_xdouble, BKZConstant) static void ComputeBKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_xdouble, BKZThresh) static void ComputeBKZThresh(xdouble *c, long beta) { NTL_TLS_GLOBAL_ACCESS(BKZConstant); NTL_TLS_GLOBAL_ACCESS(BKZThresh); BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); BKZThresh(i) = xexp(x/double(i))*BKZConstant(i); } } static void BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- BKZ_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long BKZ_XD(mat_ZZ& BB, mat_ZZ* UU, xdouble delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; xdouble t1; ZZ T1; xdouble *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); xdouble **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, m+1); xdouble **mu = mu_store.get(); UniqueArray c_store; c_store.SetLength(m+2); xdouble *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors UniqueArray b_store; b_store.SetLength(m+2); xdouble *b = b_store.get(); // squared lengths of basis vectors xdouble cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); xdouble *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); xdouble *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); xdouble *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); xdouble *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); xdouble *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get();; mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; xdouble eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); for (i = 1; i <= m; i++) { b[i] = InnerProduct(B1[i], B1[i], n); } // cerr << "\n"; // cerr << "first LLL\n"; m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, m, 1, quit); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeBKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } if (prune > 0) ComputeBKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("BKZ_XD: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } // cerr << "special case\n"; new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, jj, quit); if (new_m != h) LogicError("BKZ_XD: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } for (i = 1; i <= n; i++) conv(B1[jj][i], B(jj, i)); b[jj] = InnerProduct(B1[jj], B1[jj], n); if (b[jj] == 0) LogicError("BKZ_XD: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_LLL_XD(B, U, delta, 0, 0, B1, mu, b, c, kk+1, jj, quit); if (new_m != kk) LogicError("BKZ_XD: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; t1 = b[i-1]; b[i-1] = b[i]; b[i] = t1; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_XD: internal error"); if (quit) break; } } z = 0; } else { // LLL_XD // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_LLL_XD(B, U, delta, 0, check, B1, mu, b, c, h, h, quit); if (new_m != h) LogicError("BKZ_XD: internal error"); if (quit) break; } z++; } } } if (verb) { BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long BKZ_XD(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_XD: bad delta"); if (beta < 2) LogicError("BKZ_XD: bad block size"); return BKZ_XD(BB, &UU, to_xdouble(delta), beta, prune, check); } long BKZ_XD(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("BKZ_XD: bad delta"); if (beta < 2) LogicError("BKZ_XD: bad block size"); return BKZ_XD(BB, 0, to_xdouble(delta), beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/RR.cpp0000644417616742025610000007777214064716022016017 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL // FIXME: I just converted all the static RR's to thread local static RR's. // Perhaps I should at some point make the equivalent of an RR Register. // But be careful: certain computations, like ComputePi, actually cache // results, so that will take more work. In any case, RR is not a high // priority right now. NTL_CHEAP_THREAD_LOCAL long RR::prec = 150; void RR::SetPrecision(long p) { if (p < 53) p = 53; if (NTL_OVERFLOW(p, 1, 0)) ResourceError("RR: precision too high"); prec = p; } NTL_CHEAP_THREAD_LOCAL long RR::oprec = 10; void RR::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) ResourceError("RR: output precision too high"); oprec = p; } static void normalize1(RR& z, const ZZ& y_x, long y_e, long prec, long residual) { long len = NumBits(y_x); if (len > prec) { long correction = ZZ_RoundCorrection(y_x, len - prec, residual); RightShift(z.x, y_x, len - prec); if (correction) add(z.x, z.x, correction); z.e = y_e + len - prec; } else if (len == 0) { clear(z.x); z.e = 0; } else { z.x = y_x; z.e = y_e; } if (!IsOdd(z.x)) z.e += MakeOdd(z.x); if (z.e >= NTL_OVFBND) ResourceError("RR: overflow"); if (z.e <= -NTL_OVFBND) ResourceError("RR: underflow"); } void normalize(RR& z, const RR& y, long residual = 0) { normalize1(z, y.x, y.e, RR::prec, residual); } void MakeRR(RR& z, const ZZ& a, long e) { if (e >= NTL_OVFBND) ResourceError("MakeRR: e too big"); if (e <= -NTL_OVFBND) ResourceError("MakeRR: e too small"); normalize1(z, a, e, RR::prec, 0); } void MakeRRPrec(RR& x, const ZZ& a, long e, long p) { if (p < 1) LogicError("MakeRRPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("MakeRRPrec: precsion too big"); RRPush push; RR::prec = p; MakeRR(x, a, e); } void random(RR& z) { NTL_TLS_LOCAL(RR, t); RandomBits(t.x, RR::prec); t.e = -RR::prec; normalize(z, t); } static inline void xcopy(RR& x, const RR& a) { normalize(x, a); } // xcopy emulates old assignment semantics... // many routines here implicitly assume assignment normalizes, // but that is no longer the case as of v3.0. void ConvPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: precsion too big"); RRPush push; RR::prec = p; normalize(x, a); } void RoundToPrecision(RR& x, const RR& a, long p) { ConvPrec(x, a, p); } void conv(RR& x, const RR& a) { normalize(x, a); } long IsZero(const RR& a) { return IsZero(a.x); } long IsOne(const RR& a) { return a.e == 0 && IsOne(a.x); } long sign(const RR& a) { return sign(a.x); } void clear(RR& z) { z.e = 0; clear(z.x); } void set(RR& z) { z.e = 0; set(z.x); } void add(RR& z, const RR& a, const RR& b) { NTL_TLS_LOCAL(RR, t); if (IsZero(a.x)) { xcopy(z, b); return; } if (IsZero(b.x)) { xcopy(z, a); return; } if (a.e > b.e) { if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2) normalize(z, a, sign(b)); else { LeftShift(t.x, a.x, a.e-b.e); add(t.x, t.x, b.x); t.e = b.e; normalize(z, t); } } else if (a.e < b.e) { if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2) normalize(z, b, sign(a)); else { LeftShift(t.x, b.x, b.e-a.e); add(t.x, t.x, a.x); t.e = a.e; normalize(z, t); } } else { add(t.x, a.x, b.x); t.e = a.e; normalize(z, t); } } void AddPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1) LogicError("AddPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("AddPrec: bad precsion"); RRPush push; RR::prec = p; add(x, a, b); } void sub(RR& z, const RR& a, const RR& b) { NTL_TLS_LOCAL(RR, t); if (IsZero(a.x)) { negate(z, b); return; } if (IsZero(b.x)) { xcopy(z, a); return; } if (a.e > b.e) { if (a.e-b.e - max(RR::prec-NumBits(a.x),0) >= NumBits(b.x) + 2) normalize(z, a, -sign(b)); else { LeftShift(t.x, a.x, a.e-b.e); sub(t.x, t.x, b.x); t.e = b.e; xcopy(z, t); } } else if (a.e < b.e) { if (b.e-a.e - max(RR::prec-NumBits(b.x),0) >= NumBits(a.x) + 2) { normalize(z, b, -sign(a)); negate(z.x, z.x); } else { LeftShift(t.x, b.x, b.e-a.e); sub(t.x, a.x, t.x); t.e = a.e; xcopy(z, t); } } else { sub(t.x, a.x, b.x); t.e = a.e; normalize(z, t); } } void SubPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1) LogicError("SubPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("SubPrec: bad precsion"); RRPush push; RR::prec = p; sub(x, a, b); } void negate(RR& z, const RR& a) { xcopy(z, a); negate(z.x, z.x); } void NegatePrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("NegatePrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("NegatePrec: bad precsion"); RRPush push; RR::prec = p; negate(x, a); } void abs(RR& z, const RR& a) { xcopy(z, a); abs(z.x, z.x); } void AbsPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("AbsPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("AbsPrec: bad precsion"); RRPush push; RR::prec = p; abs(x, a); } void mul(RR& z, const RR& a, const RR& b) { NTL_TLS_LOCAL(RR, t); mul(t.x, a.x, b.x); t.e = a.e + b.e; xcopy(z, t); } void MulPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1) LogicError("MulPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("MulPrec: bad precsion"); RRPush push; RR::prec = p; mul(x, a, b); } void sqr(RR& z, const RR& a) { NTL_TLS_LOCAL(RR, t); sqr(t.x, a.x); t.e = a.e + a.e; xcopy(z, t); } void SqrPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("SqrPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("SqrPrec: bad precsion"); RRPush push; RR::prec = p; sqr(x, a); } void div(RR& z, const RR& a, const RR& b) { if (IsZero(b)) ArithmeticError("RR: division by zero"); if (IsZero(a)) { clear(z); return; } long la = NumBits(a.x); long lb = NumBits(b.x); long neg = (sign(a) != sign(b)); long k = RR::prec - la + lb + 1; if (k < 0) k = 0; NTL_TLS_LOCAL(RR, t); NTL_ZZRegister(A); NTL_ZZRegister(B); NTL_ZZRegister(R); abs(A, a.x); LeftShift(A, A, k); abs(B, b.x); DivRem(t.x, R, A, B); t.e = a.e - b.e - k; normalize(z, t, !IsZero(R)); if (neg) negate(z.x, z.x); } void DivPrec(RR& x, const RR& a, const RR& b, long p) { if (p < 1) LogicError("DivPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("DivPrec: bad precsion"); RRPush push; RR::prec = p; div(x, a, b); } void SqrRoot(RR& z, const RR& a) { if (sign(a) < 0) ArithmeticError("RR: attempt to take square root of negative number"); if (IsZero(a)) { clear(z); return; } RR t; ZZ T1, T2; long k; k = 2*RR::prec - NumBits(a.x) + 1; if (k < 0) k = 0; if ((a.e - k) & 1) k++; LeftShift(T1, a.x, k); // since k >= 2*prec - bits(a) + 1, T1 has at least 2*prec+1 bits, // thus T1 >= 2^(2*prec) SqrRoot(t.x, T1); // t.x >= 2^prec thus t.x contains the round bit t.e = (a.e - k)/2; sqr(T2, t.x); // T1-T2 is the (lower part of the) sticky bit normalize(z, t, T2 < T1); } void SqrRootPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("SqrRootPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("SqrRootPrec: bad precsion"); RRPush push; RR::prec = p; SqrRoot(x, a); } long compare(const RR& a, const RR& b) { NTL_TLS_LOCAL(RR, t); SubPrec(t, a, b, 1); return sign(t); } long operator==(const RR& a, const RR& b) { return a.e == b.e && a.x == b.x; } void trunc(RR& z, const RR& a) { NTL_TLS_LOCAL(RR, t); if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); t.e = 0; xcopy(z, t); } } void TruncPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("TruncPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("TruncPrec: bad precsion"); RRPush push; RR::prec = p; trunc(x, a); } void floor(RR& z, const RR& a) { NTL_TLS_LOCAL(RR, t); if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); if (sign(a.x) < 0) add(t.x, t.x, -1); t.e = 0; xcopy(z, t); } } void FloorPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("FloorPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("FloorPrec: bad precsion"); RRPush push; RR::prec = p; floor(x, a); } void ceil(RR& z, const RR& a) { NTL_TLS_LOCAL(RR, t); if (a.e >= 0) xcopy(z, a); else { RightShift(t.x, a.x, -a.e); if (sign(a.x) > 0) add(t.x, t.x, 1); t.e = 0; xcopy(z, t); } } void CeilPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("CeilPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("CeilPrec: bad precsion"); RRPush push; RR::prec = p; ceil(x, a); } void round(RR& z, const RR& a) { if (a.e >= 0) { xcopy(z, a); return; } long len = NumBits(a.x); if (-a.e > len) { z = 0; return; } if (-a.e == len) { if (len == 1) z = 0; else z = sign(a.x); return; } NTL_TLS_LOCAL(RR, t); ConvPrec(t, a, len+a.e); xcopy(z, t); } void RoundPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("RoundPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("RoundPrec: bad precsion"); RRPush push; RR::prec = p; round(x, a); } void conv(RR& z, const ZZ& a) { normalize1(z, a, 0, RR::prec, 0); } void ConvPrec(RR& x, const ZZ& a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(RR& z, long a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } NTL_ZZRegister(t); t = a; conv(z, t); } void ConvPrec(RR& x, long a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(RR& z, unsigned long a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } NTL_ZZRegister(t); conv(t, a); conv(z, t); } void ConvPrec(RR& x, unsigned long a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(RR& z, double a) { if (a == 0) { clear(z); return; } if (a == 1) { set(z); return; } if (!IsFinite(&a)) ArithmeticError("RR: conversion of a non-finite double"); int e; double f; NTL_TLS_LOCAL(RR, t); f = frexp(a, &e); f = f * NTL_FDOUBLE_PRECISION; f = f * 4; conv(t.x, f); t.e = e - (NTL_DOUBLE_PRECISION + 1); xcopy(z, t); } void ConvPrec(RR& x, double a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else { long sgn = sign(a.x); RightShift(z, a.x, -a.e); if (sgn < 0) sub(z, z, 1); } } void CeilToZZ(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else { long sgn = sign(a.x); RightShift(z, a.x, -a.e); if (sgn > 0) add(z, z, 1); } } void TruncToZZ(ZZ& z, const RR& a) { if (a.e >= 0) LeftShift(z, a.x, a.e); else RightShift(z, a.x, -a.e); } void RoundToZZ(ZZ& z, const RR& a) { if (a.e >= 0) { LeftShift(z, a.x, a.e); return; } long len = NumBits(a.x); if (-a.e > len) { z = 0; return; } if (-a.e == len) { if (len == 1) z = 0; else z = sign(a.x); return; } NTL_TLS_LOCAL(RR, t); ConvPrec(t, a, len+a.e); LeftShift(z, t.x, t.e); } void conv(long& z, const RR& a) { ZZ t; if (a.e >= NTL_BITS_PER_LONG) z = 0; else { conv(t, a); conv(z, t); } } void conv(double& z, const RR& aa) { double x; NTL_TLS_LOCAL(RR, a); ConvPrec(a, aa, NTL_DOUBLE_PRECISION); // round to NTL_DOUBLE_PRECISION bits to avoid double overflow conv(x, a.x); z = _ntl_ldexp(x, a.e); } void add(RR& z, const RR& a, double b) { NTL_TLS_LOCAL(RR, B); B = b; add(z, a, B); } void sub(RR& z, const RR& a, double b) { NTL_TLS_LOCAL(RR, B); B = b; sub(z, a, B); } void sub(RR& z, double a, const RR& b) { NTL_TLS_LOCAL(RR, A); A = a; sub(z, A, b); } void mul(RR& z, const RR& a, double b) { NTL_TLS_LOCAL(RR, B); B = b; mul(z, a, B); } void div(RR& z, const RR& a, double b) { NTL_TLS_LOCAL(RR, B); B = b; div(z, a, B); } void div(RR& z, double a, const RR& b) { NTL_TLS_LOCAL(RR, A); A = a; div(z, A, b); } void inv(RR& z, const RR& a) { NTL_TLS_LOCAL_INIT(RR, one, (to_RR(1))); div(z, one, a); } void InvPrec(RR& x, const RR& a, long p) { if (p < 1) LogicError("InvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("InvPrec: bad precsion"); RRPush push; RR::prec = p; inv(x, a); } long compare(const RR& a, double b) { if (b == 0) return sign(a); NTL_TLS_LOCAL(RR, B); B = b; return compare(a, B); } long operator==(const RR& a, double b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); NTL_TLS_LOCAL(RR, B); B = b; return a == B; } void power(RR& z, const RR& a, long e) { RR b, res; long n = NumBits(e); RRPush push; long p = RR::precision(); RR::SetPrecision(p + n + 10); xcopy(b, a); set(res); long i; for (i = n-1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, b); } RR::SetPrecision(p); if (e < 0) inv(z, res); else xcopy(z, res); } istream& operator>>(istream& s, RR& x) { RR v; { RRPush push; long c; long cval; long sign; ZZ a, b; if (!s) NTL_INPUT_ERROR(s, "bad RR input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; s.get(); c = s.peek(); cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); s.get(); c = s.peek(); cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) NTL_INPUT_ERROR(s, "bad RR input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; s.get(); c = s.peek(); if (c == '-') { e_sign = -1; s.get(); c = s.peek(); } else if (c == '+') { e_sign = 1; s.get(); c = s.peek(); } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) NTL_INPUT_ERROR(s, "bad RR input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) NTL_INPUT_ERROR(s, "bad RR input"); RR t1, t2; long old_p = RR::precision(); if (got1 || got2) { ConvPrec(t1, a, max(NumBits(a), 1)); ConvPrec(t2, b, NumBits(b)); if (got_e) RR::SetPrecision(old_p + 10); div(v, t1, t2); } else set(v); if (sign < 0) negate(v, v); if (got_e) { if (e >= NTL_OVFBND) ResourceError("RR input overflow"); long E; conv(E, e); if (e_sign < 0) E = -E; RR::SetPrecision(old_p + 10); power(t1, to_RR(10), E); mul(v, v, t1); } } xcopy(x, v); return s; } istream& InputPrec(RR& x, istream& s, long p) { if (p < 1) LogicError("InputPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("InputPrec: bad precsion"); RRPush push; RR::prec = p; s >> x; return s; } void conv(RR& z, const xdouble& a) { conv(z, a.mantissa()); if (a.exponent() > ((2*NTL_OVFBND)/(2*NTL_XD_HBOUND_LOG))) ResourceError("RR: overlow"); if (a.exponent() < -((2*NTL_OVFBND)/(2*NTL_XD_HBOUND_LOG))) ResourceError("RR: underflow"); z.e += a.exponent()*(2*NTL_XD_HBOUND_LOG); if (z.e >= NTL_OVFBND) ResourceError("RR: overflow"); if (z.e <= -NTL_OVFBND) ResourceError("RR: underflow"); } void ConvPrec(RR& x, const xdouble& a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(xdouble& z, const RR& a) { xdouble x; xdouble y; conv(x, a.x); power2(y, a.e); z = x*y; } void power2(RR& z, long e) { if (e >= NTL_OVFBND) ResourceError("RR: overflow"); if (e <= -NTL_OVFBND) ResourceError("RR: underflow"); set(z.x); z.e = e; } void conv(RR& z, const quad_float& a) { NTL_TLS_LOCAL(RR, hi); NTL_TLS_LOCAL(RR, lo); NTL_TLS_LOCAL(RR, res); ConvPrec(hi, a.hi, NTL_DOUBLE_PRECISION); ConvPrec(lo, a.lo, NTL_DOUBLE_PRECISION); add(res, hi, lo); z = res; } void ConvPrec(RR& x, const quad_float& a, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, a); } void conv(quad_float& z, const RR& a) { NTL_TLS_LOCAL(RR, a_hi); NTL_TLS_LOCAL(RR, a_lo); ConvPrec(a_hi, a, NTL_DOUBLE_PRECISION); // high order bits SubPrec(a_lo, a, a_hi, NTL_DOUBLE_PRECISION); // low order bits z = to_quad_float(a_hi.x)*power2_quad_float(a_hi.e) + to_quad_float(a_lo.x)*power2_quad_float(a_lo.e); } void ConvPrec(RR& x, const char *s, long p) { if (p < 1) LogicError("ConvPrec: bad precsion"); if (NTL_OVERFLOW(p, 1, 0)) ResourceError("ConvPrec: bad precsion"); RRPush push; RR::prec = p; conv(x, s); } void ReallyComputeE(RR& res) { RRPush push; long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t; s = 1; t = 1; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s); } void ComputeE(RR& res) { static NTL_CHEAP_THREAD_LOCAL long prec = 0; NTL_TLS_LOCAL(RR, e); RRPush push; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeE(e); RR::SetPrecision(p); } xcopy(res, e); } void exp(RR& res, const RR& x) { if (x >= NTL_OVFBND || x <= -NTL_OVFBND) ResourceError("RR: overflow"); RRPush push; long p = RR::precision(); // step 0: write x = n + f, n an integer and |f| <= 1/2 // careful -- we want to compute f to > p bits of precision RR f, nn; RR::SetPrecision(NTL_BITS_PER_LONG); round(nn, x); RR::SetPrecision(p + 10); sub(f, x, nn); long n = to_long(nn); // step 1: calculate t1 = e^n by repeated squaring RR::SetPrecision(p + NumBits(n) + 10); RR e; ComputeE(e); RR::SetPrecision(p + 10); RR t1; power(t1, e, n); // step 2: calculate t2 = e^f using Taylor series expansion RR::SetPrecision(p + NumBits(p) + 10); RR t2, s, s1, t; long i; s = 0; t = 1; for (i = 1; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } xcopy(t2, s); RR::SetPrecision(p); mul(res, t1, t2); } void ReallyComputeLn2(RR& res) { RRPush push; long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, 0.5); div(t, t1, i); } RR::SetPrecision(p); xcopy(res, s); } void ComputeLn2(RR& res) { static NTL_CHEAP_THREAD_LOCAL long prec = 0; NTL_TLS_LOCAL(RR, ln2); RRPush push; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeLn2(ln2); RR::SetPrecision(p); } xcopy(res, ln2); } long Lg2(const RR& x) { return NumBits(x.mantissa()) + x.exponent(); } void log(RR& res, const RR& x) { if (x <= 0) ArithmeticError("argument to log must be positive"); RRPush push; long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR y; long n; // re-write x = 2^n * (1 - y), where -1/2 < y < 1/4 (so 3/4 < 1-y < 3/2) if (x > 0.75 && x < 1.5) { n = 0; sub(y, 1, x); } else { n = Lg2(x) - 1; RR t; power2(t, -n); mul(t, t, x); while (t > 1.5) { mul(t, t, 0.5); n++; } sub(y, 1, t); } // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } if (n == 0) t = 0; else { ComputeLn2(t); mul(t, t, n); } RR::SetPrecision(p); sub(res, t, s); } void ComputeLn10(RR& res) { static NTL_CHEAP_THREAD_LOCAL long prec = 0; NTL_TLS_LOCAL(RR, ln10); RRPush push; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); log(ln10, to_RR(10)); RR::SetPrecision(p); } xcopy(res, ln10); } void log10(RR& res, const RR& x) { RRPush push; long p = RR::precision(); RR::SetPrecision(p + 10); RR ln10, t1, t2; ComputeLn10(ln10); log(t1, x); div(t2, t1, ln10); RR::SetPrecision(p); xcopy(res, t2); } void expm1(RR& res, const RR& x) { RRPush push; long p = RR::precision(); if (x < -0.5 || x > 0.5) { RR t; RR::SetPrecision(p + 10); exp(t, x); RR::SetPrecision(p); sub(res, t, 1); return; } RR::SetPrecision(p + NumBits(p) + 10); RR f; xcopy(f, x); RR s, s1, t; long i; s = 0; xcopy(t, f); for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s); } void log1p(RR& res, const RR& x) { RRPush push; long p = RR::precision(); RR y; if (x < -0.5 || x > 0.5) { RR::SetPrecision(p + 10); log(y, 1 + x); RR::SetPrecision(p); xcopy(res, y); return; } RR::SetPrecision(p + NumBits(p) + 10); negate(y, x); // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } RR::SetPrecision(p); negate(res, s); } void pow(RR& res, const RR& x, const RR& y) { if (y == 0) { res = 1; return; } if (x == 0) { res = 0; return; } if (x == 1) { res = 1; return; } if (x < 0) { ArithmeticError("pow: sorry...first argument to pow must be nonnegative"); } RRPush push; long p = RR::precision(); // calculate working precison...one could use p + NTL_BITS_PER_LONG + 10, // for example, but we want the behaviour to be machine independent. // so we calculate instead a rough approximation to log |y log(x)| RR t1, t2; long k; if (x > 0.5 && x < 1.5) { xcopy(t1, x - 1); k = Lg2(t1); } else { k = NumBits(Lg2(x)); } k += Lg2(y); if (k > NTL_BITS_PER_LONG+10) ResourceError("RR: overflow"); if (k < 0) k = 0; RR::SetPrecision(p + k + 10); t1 = y*log(x); RR::SetPrecision(p); t2 = exp(t1); res = t2; } void ReallyComputePi(RR& res) { RRPush push; long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR sum1; RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, -0.25); div(t, t1, i); } xcopy(sum1, s); RR g; inv(g, to_RR(3)); // g = 1/3 s = 0; xcopy(t, g); xcopy(t1, g); sqr(g, g); negate(g, g); // g = -1/9 for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, g); div(t, t1, i); } add(s, s, sum1); mul(s, s, 4); RR::SetPrecision(p); xcopy(res, s); } void ComputePi(RR& res) { static NTL_CHEAP_THREAD_LOCAL long prec = 0; NTL_TLS_LOCAL(RR, pi); RRPush push; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputePi(pi); RR::SetPrecision(p); } xcopy(res, pi); } void sin(RR& res, const RR& x) { if (x == 0) { res = 0; return; } if (Lg2(x) > 1000) ResourceError("sin: sorry...argument too large in absolute value"); RRPush push; long p = RR::precision(); RR pi, t1, f; RR n; // we want to make x^2 < 3, so that the series for sin(x) // converges nicely, without any nasty cancellations in the // first terms of the series. RR::SetPrecision(p + NumBits(p) + 10); if (x*x < 3) { xcopy(f, x); } else { // we want to write x/pi = n + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - n); if (f > 0.5) { n++; xcopy(f, t1 - n); } if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n != 0 && n.exponent() == 0) { // n is odd, so we negate f, which negates sin(f) xcopy(f, -f); } } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s); } void cos(RR& res, const RR& x) { if (x == 0) { res = 1; return; } if (Lg2(x) > 1000) ResourceError("cos: sorry...argument too large in absolute value"); RRPush push; long p = RR::precision(); RR pi, t1, f; RR n; // we want to write x/pi = (n+1/2) + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - (n + 0.5)); if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n == 0 || n.exponent() != 0) { // n is even, so we negate f, which negates sin(f) xcopy(f, -f); } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s); } ostream& operator<<(ostream& s, const RR& a) { if (IsZero(a)) { s << "0"; return s; } RRPush push; // we compute new_p and log_10_a precisely using sufficient // precision---this is necessary to achieve accuracy and // platform independent behaviour long temp_p = max(NumBits(RR::OutputPrecision()), NumBits(Lg2(a))) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; long new_p = to_long(RR::OutputPrecision()*log_2_10) + 20; long log_10_a = to_long(Lg2(a)/log_2_10); RR::SetPrecision(new_p); RR b; long neg; if (a < 0) { negate(b, a); neg = 1; } else { xcopy(b, a); neg = 0; } long k = RR::OutputPrecision() - log_10_a; RR c, d; power(c, to_RR(10), RR::OutputPrecision()); power(d, to_RR(10), log_10_a); div(b, b, d); mul(b, b, c); while (b < c) { mul(b, b, 10); k++; } while (b >= c) { div(b, b, 10); k--; } add(b, b, 0.5); k = -k; ZZ B; conv(B, b); long bp_len = RR::OutputPrecision()+10; UniqueArray bp_store; bp_store.SetLength(bp_len); char *bp = bp_store.get(); long len, i; len = 0; do { if (len >= bp_len) LogicError("RR output: buffer overflow"); bp[len] = IntValToChar(DivRem(B, B, 10)); len++; } while (B > 0); for (i = 0; i < len/2; i++) { char tmp; tmp = bp[i]; bp[i] = bp[len-1-i]; bp[len-1-i] = tmp; } i = len-1; while (bp[i] == '0') i--; k += (len-1-i); len = i+1; bp[len] = '\0'; if (k > 3 || k < -len - 3) { // use scientific notation if (neg) s << "-"; s << "0." << bp << "e" << (k + len); } else if (k >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < k; i++) s << "0"; } else if (k <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-k; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+k; i++) s << bp[i]; s << "."; for (i = len+k; i < len; i++) s << bp[i]; } return s; } NTL_END_IMPL ntl-11.5.1/src/WordVector.cpp0000644417616742025610000001655314064716022017560 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL void WordVector::DoSetLength(long n) { long m; if (n < 0) { LogicError("negative length in vector::SetLength"); } if (NTL_OVERFLOW(n, NTL_BITS_PER_LONG, 0)) ResourceError("length too big in vector::SetLength"); if (n == 0) { if (rep) rep[-1] = 0; return; } if (!rep) { m = ((n+NTL_WordVectorMinAlloc-1)/NTL_WordVectorMinAlloc) * NTL_WordVectorMinAlloc; if (NTL_OVERFLOW(m, NTL_BITS_PER_LONG, 0)) ResourceError("length too big in vector::SetLength"); _ntl_ulong *p = (_ntl_ulong *) NTL_SNS_MALLOC(m, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong)); if (!p) { MemoryError(); } rep = p+2; rep[-1] = n; rep[-2] = m << 1; return; } long max_length = (rep[-2] >> 1); if (n <= max_length) { rep[-1] = n; return; } long frozen = (rep[-2] & 1); if (frozen) LogicError("Cannot grow this WordVector"); m = max(n, _ntl_vec_grow(max_length)); m = ((m+NTL_WordVectorMinAlloc-1)/NTL_WordVectorMinAlloc)*NTL_WordVectorMinAlloc; _ntl_ulong *p = rep - 2; if (NTL_OVERFLOW(m, NTL_BITS_PER_LONG, 0)) ResourceError("length too big in vector::SetLength"); p = (_ntl_ulong *) NTL_SNS_REALLOC(p, m, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong)); if (!p) { MemoryError(); } rep = p+2; rep[-1] = n; rep[-2] = m << 1; } void WordVector::SetMaxLength(long n) { long OldLength = length(); DoSetLength(n); if (rep) rep[-1] = OldLength; } WordVector& WordVector::operator=(const WordVector& a) { long i, n; _ntl_ulong *p; const _ntl_ulong *ap; if (this == &a) return *this; n = a.length(); ap = a.elts(); SetLength(n); p = elts(); for (i = 0; i < n; i++) p[i] = ap[i]; return *this; } WordVector::~WordVector() { if (!rep) return; if (rep[-2] & 1) TerminalError("Cannot free this WordVector"); free(rep-2); } void WordVector::kill() { if (!rep) return; if (rep[-2] & 1) LogicError("Cannot free this WordVector"); free(rep-2); rep = 0; } void CopySwap(WordVector& x, WordVector& y) { NTL_TLS_LOCAL(WordVector, t); WordVectorWatcher watch_t(t); long sz_x = x.length(); long sz_y = y.length(); long sz = (sz_x > sz_y) ? sz_x : sz_y; x.SetMaxLength(sz); y.SetMaxLength(sz); // EXCEPTIONS: all of the above ensures that swap provides strong ES t = x; x = y; y = t; } void WordVector::swap(WordVector& y) { if ((this->rep && (this->rep[-2] & 1)) || (y.rep && (y.rep[-2] & 1))) { CopySwap(*this, y); return; } _ntl_swap(this->rep, y.rep); } void WordVector::append(_ntl_ulong a) { long l = this->length(); this->SetLength(l+1); (*this)[l] = a; } void WordVector::append(const WordVector& w) { long l = this->length(); long m = w.length(); long i; this->SetLength(l+m); for (i = 0; i < m; i++) (*this)[l+i] = w[i]; } istream & operator>>(istream& s, WordVector& a) { WordVector ibuf; long c; long n; if (!s) NTL_INPUT_ERROR(s, "bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { NTL_INPUT_ERROR(s, "bad vector input"); } n = 0; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (n % NTL_WordVectorInputBlock == 0) ibuf.SetMaxLength(n + NTL_WordVectorInputBlock); n++; ibuf.SetLength(n); if (!(s >> ibuf[n-1])) NTL_INPUT_ERROR(s, "bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) NTL_INPUT_ERROR(s, "bad vector input"); s.get(); a = ibuf; return s; } ostream& operator<<(ostream& s, const WordVector& a) { long i, n; n = a.length(); s << '['; for (i = 0; i < n; i++) { s << a[i]; if (i < n-1) s << " "; } s << ']'; return s; } long operator==(const WordVector& a, const WordVector& b) { long n = a.length(); if (b.length() != n) return 0; const _ntl_ulong* ap = a.elts(); const _ntl_ulong* bp = b.elts(); long i; for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } long operator!=(const WordVector& a, const WordVector& b) { return !(a == b); } long InnerProduct(const WordVector& a, const WordVector& b) { long n = min(a.length(), b.length()); const _ntl_ulong *ap = a.elts(); const _ntl_ulong *bp = b.elts(); _ntl_ulong acc; long i; acc = 0; for (i = 0; i < n; i++) acc ^= ap[i] & bp[i]; #if (NTL_BITS_PER_LONG == 32) acc ^= acc >> 16; acc ^= acc >> 8; acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #elif (NTL_BITS_PER_LONG == 64) acc ^= acc >> 32; acc ^= acc >> 16; acc ^= acc >> 8; acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #else _ntl_ulong t = acc; while (t) { t = t >> 8; acc ^= t; } acc ^= acc >> 4; acc ^= acc >> 2; acc ^= acc >> 1; acc &= 1; #endif return long(acc); } void ShiftAdd(_ntl_ulong *cp, const _ntl_ulong* ap, long sa, long n) // c = c + (a << n) { if (sa == 0) return; long i; long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn == 0) { for (i = sa+wn-1; i >= wn; i--) cp[i] ^= ap[i-wn]; } else { _ntl_ulong t = ap[sa-1] >> (NTL_BITS_PER_LONG-bn); if (t) cp[sa+wn] ^= t; for (i = sa+wn-1; i >= wn+1; i--) cp[i] ^= (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); cp[wn] ^= ap[0] << bn; } } long WV_BlockConstructAlloc(WordVector& x, long d, long n) { long nwords, nbytes, AllocAmt, m, j; _ntl_ulong *p, *q; /* check n value */ if (n <= 0) LogicError("block construct: n must be positive"); /* check d value */ if (d <= 0) LogicError("block construct: d must be positive"); if (NTL_OVERFLOW(d, NTL_BITS_PER_LONG, 0) || NTL_OVERFLOW(d, sizeof(_ntl_ulong), 2*sizeof(_ntl_ulong))) ResourceError("block construct: d too large"); nwords = d + 2; nbytes = nwords*sizeof(_ntl_ulong); AllocAmt = (NTL_MAX_ALLOC_BLOCK - sizeof(_ntl_ulong)) / nbytes; if (AllocAmt == 0) AllocAmt = 1; if (AllocAmt < n) m = AllocAmt; else m = n; p = (_ntl_ulong *) NTL_SNS_MALLOC(m, nbytes, sizeof(_ntl_ulong)); if (!p) MemoryError(); *p = m; q = p+3; x.rep = q; for (j = 0; j < m; j++) { q[-2] = (d << 1) | 1; q[-1] = 0; q += nwords; } return m; } void WV_BlockConstructSet(WordVector& x, WordVector& y, long i) { long d, size; d = x.rep[-2] >> 1; size = d + 2; y.rep = x.rep + i*size; } long WV_BlockDestroy(WordVector& x) { long m; _ntl_ulong *p; p = x.rep - 3; m = (long) *p; free(p); return m; } long WV_storage(long d) { return (d + 2)*sizeof(_ntl_ulong) + sizeof(WordVector); } NTL_END_IMPL ntl-11.5.1/src/ZZ.cpp0000644417616742025610000032055014064716022016020 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include #include #if defined(NTL_HAVE_AVX2) #include #elif defined(NTL_HAVE_SSSE3) #include #include #endif #if defined(NTL_HAVE_KMA) #include #endif NTL_START_IMPL const ZZ& ZZ::zero() { static const ZZ z; // GLOBAL (relies on C++11 thread-safe init) return z; } const ZZ& ZZ_expo(long e) { NTL_TLS_LOCAL(ZZ, expo_helper); conv(expo_helper, e); return expo_helper; } void AddMod(ZZ& x, const ZZ& a, long b, const ZZ& n) { NTL_ZZRegister(B); conv(B, b); AddMod(x, a, B, n); } void SubMod(ZZ& x, const ZZ& a, long b, const ZZ& n) { NTL_ZZRegister(B); conv(B, b); SubMod(x, a, B, n); } void SubMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { NTL_ZZRegister(A); conv(A, a); SubMod(x, A, b, n); } // ****** input and output static NTL_CHEAP_THREAD_LOCAL long iodigits = 0; static NTL_CHEAP_THREAD_LOCAL long ioradix = 0; // iodigits is the greatest integer such that 10^{iodigits} < NTL_WSP_BOUND // ioradix = 10^{iodigits} static void InitZZIO() { long x; x = (NTL_WSP_BOUND-1)/10; iodigits = 0; ioradix = 1; while (x) { x = x / 10; iodigits++; ioradix = ioradix * 10; } if (iodigits <= 0) TerminalError("problem with I/O"); } istream& operator>>(istream& s, ZZ& x) { long c; long cval; long sign; long ndigits; long acc; NTL_ZZRegister(a); if (!s) NTL_INPUT_ERROR(s, "bad ZZ input"); if (!iodigits) InitZZIO(); a = 0; SkipWhiteSpace(s); c = s.peek(); if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) NTL_INPUT_ERROR(s, "bad ZZ input"); ndigits = 0; acc = 0; while (cval >= 0 && cval <= 9) { acc = acc*10 + cval; ndigits++; if (ndigits == iodigits) { mul(a, a, ioradix); add(a, a, acc); ndigits = 0; acc = 0; } s.get(); c = s.peek(); cval = CharToIntVal(c); } if (ndigits != 0) { long mpy = 1; while (ndigits > 0) { mpy = mpy * 10; ndigits--; } mul(a, a, mpy); add(a, a, acc); } if (sign == -1) negate(a, a); x = a; return s; } // The class _ZZ_local_stack should be defined in an empty namespace, // but since I don't want to rely on namespaces, we just give it a funny // name to avoid accidental name clashes. struct _ZZ_local_stack { long top; Vec data; _ZZ_local_stack() { top = -1; } long pop() { return data[top--]; } long empty() { return (top == -1); } void push(long x); }; void _ZZ_local_stack::push(long x) { if (top+1 >= data.length()) data.SetLength(max(32, long(1.414*data.length()))); top++; data[top] = x; } static void PrintDigits(ostream& s, long d, long justify) { NTL_TLS_LOCAL_INIT(Vec, buf, (INIT_SIZE, iodigits)); long i = 0; while (d) { buf[i] = IntValToChar(d % 10); d = d / 10; i++; } if (justify) { long j = iodigits - i; while (j > 0) { s << "0"; j--; } } while (i > 0) { i--; s << buf[i]; } } ostream& operator<<(ostream& s, const ZZ& a) { ZZ b; _ZZ_local_stack S; long r; long k; if (!iodigits) InitZZIO(); b = a; k = sign(b); if (k == 0) { s << "0"; return s; } if (k < 0) { s << "-"; negate(b, b); } do { r = DivRem(b, b, ioradix); S.push(r); } while (!IsZero(b)); r = S.pop(); PrintDigits(s, r, 0); while (!S.empty()) { r = S.pop(); PrintDigits(s, r, 1); } return s; } long GCD(long a, long b) { long u, v, t, x; if (a < 0) { if (a < -NTL_MAX_LONG) ResourceError("GCD: integer overflow"); a = -a; } if (b < 0) { if (b < -NTL_MAX_LONG) ResourceError("GCD: integer overflow"); b = -b; } if (b==0) x = a; else { u = a; v = b; do { t = u % v; u = v; v = t; } while (v != 0); x = u; } return x; } void XGCD(long& d, long& s, long& t, long a, long b) { long u, v, u0, v0, u1, v1, u2, v2, q, r; long aneg = 0, bneg = 0; if (a < 0) { if (a < -NTL_MAX_LONG) ResourceError("XGCD: integer overflow"); a = -a; aneg = 1; } if (b < 0) { if (b < -NTL_MAX_LONG) ResourceError("XGCD: integer overflow"); b = -b; bneg = 1; } u1=1; v1=0; u2=0; v2=1; u = a; v = b; while (v != 0) { q = u / v; r = u % v; u = v; v = r; u0 = u2; v0 = v2; u2 = u1 - q*u2; v2 = v1- q*v2; u1 = u0; v1 = v0; } if (aneg) u1 = -u1; if (bneg) v1 = -v1; d = u; s = u1; t = v1; } long InvModStatus(long& x, long a, long n) { long d, s, t; XGCD(d, s, t, a, n); if (d != 1) { x = d; return 1; } else { if (s < 0) x = s + n; else x = s; return 0; } } long InvMod(long a, long n) { long d, s, t; XGCD(d, s, t, a, n); if (d != 1) { InvModError("InvMod: inverse undefined"); } if (s < 0) return s + n; else return s; } long PowerMod(long a, long ee, long n) { long x, y; unsigned long e; if (ee < 0) e = - ((unsigned long) ee); else e = ee; x = 1; y = a; while (e) { if (e & 1) x = MulMod(x, y, n); y = MulMod(y, y, n); e = e >> 1; } if (ee < 0) x = InvMod(x, n); return x; } static long MillerWitness_sp(long n, long x) { long m, y, z; long j, k; if (x == 0) return 0; m = n - 1; k = 0; while((m & 1) == 0) { m = m >> 1; k++; } // n - 1 == 2^k * m, m odd z = PowerMod(x, m, n); if (z == 1) return 0; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 1; return 0; } long ProbPrime(long n, long NumTrials) { if (NumTrials < 0) NumTrials = 0; long m, x, y, z; long i, j, k; if (n <= 1) return 0; if (n == 2) return 1; if (n % 2 == 0) return 0; if (n == 3) return 1; if (n % 3 == 0) return 0; if (n == 5) return 1; if (n % 5 == 0) return 0; if (n == 7) return 1; if (n % 7 == 0) return 0; if (n == 11) return 1; if (n % 11 == 0) return 0; if (n == 13) return 1; if (n % 13 == 0) return 0; if (n >= NTL_SP_BOUND) { return ProbPrime(to_ZZ(n), NumTrials); } m = n - 1; k = 0; while((m & 1) == 0) { m = m >> 1; k++; } // n - 1 == 2^k * m, m odd for (i = 0; i < NumTrials+1; i++) { // for consistency with the multi-precision version, // we first see if 2 is a witness, so we really do // NumTrials+1 tests if (i == 0) x = 2; else { do { x = RandomBnd(n); } while (x == 0); // x == 0 is not a useful candidate for a witness! } z = PowerMod(x, m, n); if (z == 1) continue; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; } return 1; } long MillerWitness(const ZZ& n, const ZZ& x) { if (n.SinglePrecision()) { return MillerWitness_sp(to_long(n), to_long(x)); } ZZ m, y, z; long j, k; if (x == 0) return 0; add(m, n, -1); k = MakeOdd(m); // n - 1 == 2^k * m, m odd PowerMod(z, x, m, n); if (z == 1) return 0; j = 0; do { y = z; SqrMod(z, y, n); j++; } while (j != k && z != 1); if (z != 1) return 1; add(y, y, 1); if (y != n) return 1; return 0; } // ComputePrimeBound computes a reasonable bound for trial // division in the Miller-Rabin test. // It is computed a bit on the "low" side, since being a bit // low doesn't hurt much, but being too high can hurt a lot. // See the paper "Fast generation of prime numbers and secure // public-key cryptographic parameters" by Ueli Maurer. // In that paper, it is calculated that the optimal bound in // roughly T_exp/T_div, where T_exp is the time for an exponentiation // and T_div is is the time for a single precision division. // Of course, estimating these times is a bit tricky, and // the values we use are based on experimentation, assuming // GMP is being used. I've tested this on various bit lengths // up to 16,000, and they seem to be pretty close to optimal. static long ComputePrimeBound(long bn) { long wn = (bn+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS; long fn; if (wn <= 36) fn = wn/4 + 1; else fn = long(1.67*sqrt(double(wn))); long prime_bnd; if (NumBits(bn) + NumBits(fn) > NTL_SP_NBITS) prime_bnd = NTL_SP_BOUND; else prime_bnd = bn*fn; return prime_bnd; } long ProbPrime(const ZZ& n, long NumTrials) { if (NumTrials < 0) NumTrials = 0; if (n <= 1) return 0; if (n.SinglePrecision()) { return ProbPrime(to_long(n), NumTrials); } long prime_bnd = ComputePrimeBound(NumBits(n)); PrimeSeq s; long p; p = s.next(); while (p && p < prime_bnd) { if (rem(n, p) == 0) return 0; p = s.next(); } ZZ W; W = 2; // first try W == 2....the exponentiation // algorithm runs slightly faster in this case if (MillerWitness(n, W)) return 0; long i; for (i = 0; i < NumTrials; i++) { do { RandomBnd(W, n); } while (W == 0); // W == 0 is not a useful candidate for a witness! if (MillerWitness(n, W)) return 0; } return 1; } static void MultiThreadedRandomPrime(ZZ& n, long l, long NumTrials) { long nt = AvailableThreads(); const long LOCAL_ITER_BOUND = 8; // since resetting the PRG comes at a certain cost, // we perform a few iterations with each reset to // amortize the reset cost. unsigned long initial_counter = 0; ZZ seed; RandomBits(seed, 256); for (;;) { AtomicLowWaterMark low_water_mark(-1UL); AtomicCounter counter(initial_counter); Vec< UniquePtr > result(INIT_SIZE, nt); Vec result_ctr(INIT_SIZE, nt, -1UL); NTL_EXEC_INDEX(nt, index) RandomStreamPush push; SetSeed(seed); RandomStream& stream = GetCurrentRandomStream(); ZZ cand; while (low_water_mark == -1UL) { unsigned long local_ctr = counter.inc(); if (local_ctr >> (NTL_BITS_PER_NONCE-1)) { // counter overflow...rather academic break; } stream.set_nonce(local_ctr); for (long iter = 0; iter < LOCAL_ITER_BOUND && local_ctr <= low_water_mark; iter++) { RandomLen(cand, l); if (!IsOdd(cand)) add(cand, cand, 1); if (ProbPrime(cand, 0)) { result[index].make(cand); result_ctr[index] = local_ctr; low_water_mark.UpdateMin(local_ctr); break; } } } NTL_EXEC_INDEX_END // find index of low_water_mark unsigned long low_water_mark1 = low_water_mark; long low_water_index = -1; for (long index = 0; index < nt; index++) { if (result_ctr[index] == low_water_mark1) { low_water_index = index; break; } } if (low_water_index == -1) { // counter overflow...rather academic initial_counter = 0; RandomBits(seed, 256); continue; } ZZ N; N = *result[low_water_index]; Vec W(INIT_SIZE, NumTrials); for (long i = 0; i < NumTrials; i++) { do { RandomBnd(W[i], N); } while (W[i] == 0); } AtomicBool tests_pass(true); NTL_EXEC_RANGE(NumTrials, first, last) for (long i = first; i < last && tests_pass; i++) { if (MillerWitness(N, W[i])) tests_pass = false; } NTL_EXEC_RANGE_END if (tests_pass) { n = N; return; } // very unlikey to get here initial_counter = low_water_mark1 + 1; } } void RandomPrime(ZZ& n, long l, long NumTrials) { if (NumTrials < 0) NumTrials = 0; if (l >= 256) { MultiThreadedRandomPrime(n, l, NumTrials); return; } if (l <= 1) LogicError("RandomPrime: l out of range"); if (l == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } do { RandomLen(n, l); if (!IsOdd(n)) add(n, n, 1); } while (!ProbPrime(n, NumTrials)); } void OldRandomPrime(ZZ& n, long l, long NumTrials) { if (l <= 1) LogicError("RandomPrime: l out of range"); if (l == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } do { RandomLen(n, l); if (!IsOdd(n)) add(n, n, 1); } while (!ProbPrime(n, NumTrials)); } void NextPrime(ZZ& n, const ZZ& m, long NumTrials) { ZZ x; if (m <= 2) { n = 2; return; } x = m; while (!ProbPrime(x, NumTrials)) add(x, x, 1); n = x; } long NextPrime(long m, long NumTrials) { long x; if (m <= 2) return 2; x = m; while (x < NTL_SP_BOUND && !ProbPrime(x, NumTrials)) x++; if (x >= NTL_SP_BOUND) ResourceError("NextPrime: no more primes"); return x; } long NextPowerOfTwo(long m) { long k; unsigned long n, um; if (m < 0) return 0; um = m; n = 1; k = 0; while (n < um) { n = n << 1; k++; } if (k >= NTL_BITS_PER_LONG-1) ResourceError("NextPowerOfTwo: overflow"); return k; } long bit(long a, long k) { unsigned long aa; if (a < 0) aa = - ((unsigned long) a); else aa = a; if (k < 0 || k >= NTL_BITS_PER_LONG) return 0; else return long((aa >> k) & 1); } long divide(ZZ& q, const ZZ& a, const ZZ& b) { NTL_ZZRegister(qq); NTL_ZZRegister(r); if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsOne(b)) { q = a; return 1; } DivRem(qq, r, a, b); if (!IsZero(r)) return 0; q = qq; return 1; } long divide(const ZZ& a, const ZZ& b) { NTL_ZZRegister(r); if (IsZero(b)) return IsZero(a); if (IsOne(b)) return 1; rem(r, a, b); return IsZero(r); } long divide(ZZ& q, const ZZ& a, long b) { NTL_ZZRegister(qq); if (!b) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (b == 1) { q = a; return 1; } long r = DivRem(qq, a, b); if (r) return 0; q = qq; return 1; } long divide(const ZZ& a, long b) { if (!b) return IsZero(a); if (b == 1) { return 1; } long r = rem(a, b); return (r == 0); } void InvMod(ZZ& x, const ZZ& a, const ZZ& n) { // NOTE: the underlying LIP routines write to the first argument, // even if inverse is undefined NTL_ZZRegister(xx); if (InvModStatus(xx, a, n)) InvModError("InvMod: inverse undefined", a, n); x = xx; } void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n) { // NOTE: this ensures that all modular inverses are computed // in the routine InvMod above, rather than the LIP-internal // modular inverse routine if (e < 0) { ZZ a_inv; ZZ e_neg; InvMod(a_inv, a, n); negate(e_neg, e); LowLevelPowerMod(x, a_inv, e_neg, n); } else LowLevelPowerMod(x, a, e, n); } #ifdef NTL_EXCEPTIONS void InvModError(const char *s, const ZZ& a, const ZZ& n) { throw InvModErrorObject(s, a, n); } #else void InvModError(const char *s, const ZZ& a, const ZZ& n) { TerminalError(s); } #endif long RandomPrime_long(long l, long NumTrials) { if (NumTrials < 0) NumTrials = 0; if (l <= 1 || l >= NTL_BITS_PER_LONG) ResourceError("RandomPrime: length out of range"); long n; do { n = RandomLen_long(l); } while (!ProbPrime(n, NumTrials)); return n; } static Lazy< Vec > lowsieve_storage; // This is a GLOBAL VARIABLE PrimeSeq::PrimeSeq() { movesieve = 0; pshift = -1; pindex = -1; exhausted = 0; } long PrimeSeq::next() { if (exhausted) { return 0; } if (pshift < 0) { shift(0); return 2; } for (;;) { const char *p = movesieve; long i = pindex; while ((++i) < NTL_PRIME_BND) { if (p[i]) { pindex = i; return pshift + 2 * i + 3; } } long newshift = pshift + 2*NTL_PRIME_BND; if (newshift > 2 * NTL_PRIME_BND * (2 * NTL_PRIME_BND + 1)) { /* end of the road */ exhausted = 1; return 0; } shift(newshift); } } void PrimeSeq::shift(long newshift) { long i; long j; long jstep; long jstart; long ibound; char *p; if (!lowsieve_storage.built()) start(); const char *lowsieve = lowsieve_storage->elts(); if (newshift < 0) { pshift = -1; } else if (newshift == 0) { pshift = 0; movesieve = lowsieve; } else if (newshift != pshift) { if (movesieve_mem.length() == 0) { movesieve_mem.SetLength(NTL_PRIME_BND); } pshift = newshift; movesieve = p = movesieve_mem.elts(); for (i = 0; i < NTL_PRIME_BND; i++) p[i] = 1; jstep = 3; ibound = pshift + 2 * NTL_PRIME_BND + 1; for (i = 0; jstep * jstep <= ibound; i++) { if (lowsieve[i]) { if (!((jstart = (pshift + 2) / jstep + 1) & 1)) jstart++; if (jstart <= jstep) jstart = jstep; jstart = (jstart * jstep - pshift - 3) / 2; for (j = jstart; j < NTL_PRIME_BND; j += jstep) p[j] = 0; } jstep += 2; } } pindex = -1; exhausted = 0; } void PrimeSeq::start() { long i; long j; long jstep; long jstart; long ibnd; char *p; do { Lazy< Vec >::Builder builder(lowsieve_storage); if (!builder()) break; UniquePtr< Vec > ptr; ptr.make(); ptr->SetLength(NTL_PRIME_BND); p = ptr->elts(); for (i = 0; i < NTL_PRIME_BND; i++) p[i] = 1; jstep = 1; jstart = -1; ibnd = (SqrRoot(2 * NTL_PRIME_BND + 1) - 3) / 2; for (i = 0; i <= ibnd; i++) { jstart += 2 * ((jstep += 2) - 1); if (p[i]) for (j = jstart; j < NTL_PRIME_BND; j += jstep) p[j] = 0; } builder.move(ptr); } while (0); } void PrimeSeq::reset(long b) { if (b > (2*NTL_PRIME_BND+1)*(2*NTL_PRIME_BND+1)) { exhausted = 1; return; } if (b <= 2) { shift(-1); return; } if ((b & 1) == 0) b++; shift(((b-3) / (2*NTL_PRIME_BND))* (2*NTL_PRIME_BND)); pindex = (b - pshift - 3)/2 - 1; } long Jacobi(const ZZ& aa, const ZZ& nn) { ZZ a, n; long t, k; long d; a = aa; n = nn; t = 1; while (a != 0) { k = MakeOdd(a); d = trunc_long(n, 3); if ((k & 1) && (d == 3 || d == 5)) t = -t; if (trunc_long(a, 2) == 3 && (d & 3) == 3) t = -t; swap(a, n); rem(a, a, n); } if (n == 1) return t; else return 0; } void SqrRootMod(ZZ& x, const ZZ& aa, const ZZ& nn) { if (aa == 0 || aa == 1) { x = aa; return; } // at this point, we must have nn >= 5 if (trunc_long(nn, 2) == 3) { // special case, n = 3 (mod 4) ZZ n, a, e, z; n = nn; a = aa; add(e, n, 1); RightShift(e, e, 2); PowerMod(z, a, e, n); x = z; return; } ZZ n, m; int h, nlen; n = nn; nlen = NumBits(n); sub(m, n, 1); h = MakeOdd(m); // h >= 2 if (nlen > 50 && h < SqrRoot(nlen)) { long i, j; ZZ a, b, a_inv, c, r, m1, d; a = aa; InvMod(a_inv, a, n); if (h == 2) b = 2; else { do { RandomBnd(b, n); } while (Jacobi(b, n) != -1); } PowerMod(c, b, m, n); add(m1, m, 1); RightShift(m1, m1, 1); PowerMod(r, a, m1, n); for (i = h-2; i >= 0; i--) { SqrMod(d, r, n); MulMod(d, d, a_inv, n); for (j = 0; j < i; j++) SqrMod(d, d, n); if (!IsOne(d)) MulMod(r, r, c, n); SqrMod(c, c, n); } x = r; return; } long i, k; ZZ ma, t, u, v, e; ZZ t1, t2, t3, t4; n = nn; NegateMod(ma, aa, n); // find t such that t^2 - 4*a is not a square MulMod(t1, ma, 4, n); do { RandomBnd(t, n); SqrMod(t2, t, n); AddMod(t2, t2, t1, n); } while (Jacobi(t2, n) != -1); // compute u*X + v = X^{(n+1)/2} mod f, where f = X^2 - t*X + a add(e, n, 1); RightShift(e, e, 1); u = 0; v = 1; k = NumBits(e); for (i = k - 1; i >= 0; i--) { add(t2, u, v); sqr(t3, t2); // t3 = (u+v)^2 sqr(t1, u); sqr(t2, v); sub(t3, t3, t1); sub(t3, t3, t2); // t1 = u^2, t2 = v^2, t3 = 2*u*v rem(t1, t1, n); mul(t4, t1, t); add(t4, t4, t3); rem(u, t4, n); mul(t4, t1, ma); add(t4, t4, t2); rem(v, t4, n); if (bit(e, i)) { MulMod(t1, u, t, n); AddMod(t1, t1, v, n); MulMod(v, u, ma, n); u = t1; } } x = v; } // Chinese Remaindering. // // This version in new to v3.7, and is significantly // simpler and faster than the previous version. // // This function takes as input g, a, G, p, // such that a > 0, 0 <= G < p, and gcd(a, p) = 1. // It computes a' = a*p and g' such that // * g' = g (mod a); // * g' = G (mod p); // * -a'/2 < g' <= a'/2. // It then sets g := g' and a := a', and returns 1 iff g has changed. // // Under normal use, the input value g satisfies -a/2 < g <= a/2; // however, this was not documented or enforced in earlier versions, // so to maintain backward compatability, no restrictions are placed // on g. This routine runs faster, though, if -a/2 < g <= a/2, // and the first thing the routine does is to make this condition // hold. // // Also, under normal use, both a and p are odd; however, the routine // will still work even if this is not so. // // The routine is based on the following simple fact. // // Let -a/2 < g <= a/2, and let h satisfy // * g + a h = G (mod p); // * -p/2 < h <= p/2. // Further, if p = 2*h and g > 0, set // g' := g - a h; // otherwise, set // g' := g + a h. // Then g' so defined satisfies the above requirements. // // It is trivial to see that g's satisfies the congruence conditions. // The only thing is to check that the "balancing" condition // -a'/2 < g' <= a'/2 also holds. long CRT(ZZ& gg, ZZ& a, long G, long p) { if (p >= NTL_SP_BOUND) { ZZ GG, pp; conv(GG, G); conv(pp, p); return CRT(gg, a, GG, pp); } long modified = 0; NTL_ZZRegister(g); if (!CRTInRange(gg, a)) { modified = 1; ZZ a1; rem(g, gg, a); RightShift(a1, a, 1); if (g > a1) sub(g, g, a); } else g = gg; long p1; p1 = p >> 1; long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long h; h = rem(g, p); h = SubMod(G, h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!(p & 1) && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } mul(a, a, p); gg = g; return modified; } long CRT(ZZ& gg, ZZ& a, const ZZ& G, const ZZ& p) { long modified = 0; ZZ g; if (!CRTInRange(gg, a)) { modified = 1; ZZ a1; rem(g, gg, a); RightShift(a1, a, 1); if (g > a1) sub(g, g, a); } else g = gg; ZZ p1; RightShift(p1, p, 1); ZZ a_inv; rem(a_inv, a, p); InvMod(a_inv, a_inv, p); ZZ h; rem(h, g, p); SubMod(h, G, h, p); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); if (h != 0) { modified = 1; ZZ ah; mul(ah, a, h); if (!IsOdd(p) && g > 0 && (h == p1)) sub(g, g, ah); else add(g, g, ah); } mul(a, a, p); gg = g; return modified; } void sub(ZZ& x, long a, const ZZ& b) { NTL_ZZRegister(A); conv(A, a); sub(x, A, b); } void power2(ZZ& x, long e) { if (e < 0) ArithmeticError("power2: negative exponent"); set(x); LeftShift(x, x, e); } void bit_and(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_and(x, a, B); } void bit_or(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_or(x, a, B); } void bit_xor(ZZ& x, const ZZ& a, long b) { NTL_ZZRegister(B); conv(B, b); bit_xor(x, a, B); } long power_long(long a, long e) { if (e < 0) ArithmeticError("power_long: negative exponent"); if (e == 0) return 1; if (a == 1) return 1; if (a == -1) { if (e & 1) return -1; else return 1; } // no overflow check --- result is computed correctly // modulo word size unsigned long res = 1; unsigned long aa = a; long i; for (i = 0; i < e; i++) res *= aa; return to_long(res); } // ======================= new PRG stuff ====================== #if (NTL_BITS_PER_INT32 == 32) #define INT32MASK(x) (x) #else #define INT32MASK(x) ((x) & _ntl_uint32(0xffffffff)) #endif // SHA256 code adapted from an implementauin by Brad Conte. // The following is from his original source files. /********************************************************************* * Filename: sha256.c * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA-256 hashing algorithm. SHA-256 is one of the three algorithms in the SHA2 specification. The others, SHA-384 and SHA-512, are not offered in this implementation. Algorithm specification can be found here: * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf This implementation uses little endian byte order. *********************************************************************/ // And the following is from the description at // https://github.com/B-Con/crypto-algorithms /********************************************************************* These are basic implementations of standard cryptography algorithms, written by Brad Conte (brad@bradconte.com) from scratch and without any cross-licensing. They exist to provide publically accessible, restriction-free implementations of popular cryptographic algorithms, like AES and SHA-1. These are primarily intended for educational and pragmatic purposes (such as comparing a specification to actual implementation code, or for building an internal application that computes test vectors for a product). The algorithms have been tested against standard test vectors. This code is released into the public domain free of any restrictions. The author requests acknowledgement if the code is used, but does not require it. This code is provided free of any liability and without any quality claims by the author. Note that these are not cryptographically secure implementations. They have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations. These algorithms are not optimized for speed or space. They are primarily designed to be easy to read, although some basic optimization techniques have been employed. *********************************************************************/ #define SHA256_BLOCKSIZE (64) #define SHA256_HASHSIZE (32) // DBL_INT_ADD treats two unsigned ints a and b as one 64-bit integer and adds c to it static inline void DBL_INT_ADD(_ntl_uint32& a, _ntl_uint32& b, _ntl_uint32 c) { _ntl_uint32 aa = INT32MASK(a); if (aa > INT32MASK(_ntl_uint32(0xffffffff) - c)) b++; a = aa + c; } #define ROTLEFT(a,b) (((a) << (b)) | (INT32MASK(a) >> (32-(b)))) #define ROTRIGHT(a,b) ((INT32MASK(a) >> (b)) | ((a) << (32-(b)))) #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ (INT32MASK(x) >> 3)) #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ (INT32MASK(x) >> 10)) struct SHA256_CTX { unsigned char data[64]; _ntl_uint32 datalen; _ntl_uint32 bitlen[2]; _ntl_uint32 state[8]; }; static const _ntl_uint32 sha256_const[64] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 }; static void sha256_transform(SHA256_CTX& ctx, unsigned char *data) { _ntl_uint32 a,b,c,d,e,f,g,h,i,j,t1,t2,m[64]; for (i=0,j=0; i < 16; ++i, j += 4) m[i] = (data[j] << 24) | (data[j+1] << 16) | (data[j+2] << 8) | (data[j+3]); for ( ; i < 64; ++i) m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16]; a = ctx.state[0]; b = ctx.state[1]; c = ctx.state[2]; d = ctx.state[3]; e = ctx.state[4]; f = ctx.state[5]; g = ctx.state[6]; h = ctx.state[7]; for (i = 0; i < 64; ++i) { t1 = h + EP1(e) + CH(e,f,g) + sha256_const[i] + m[i]; t2 = EP0(a) + MAJ(a,b,c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } ctx.state[0] += a; ctx.state[1] += b; ctx.state[2] += c; ctx.state[3] += d; ctx.state[4] += e; ctx.state[5] += f; ctx.state[6] += g; ctx.state[7] += h; } static void sha256_init(SHA256_CTX& ctx) { ctx.datalen = 0; ctx.bitlen[0] = 0; ctx.bitlen[1] = 0; ctx.state[0] = 0x6a09e667; ctx.state[1] = 0xbb67ae85; ctx.state[2] = 0x3c6ef372; ctx.state[3] = 0xa54ff53a; ctx.state[4] = 0x510e527f; ctx.state[5] = 0x9b05688c; ctx.state[6] = 0x1f83d9ab; ctx.state[7] = 0x5be0cd19; } static void sha256_update(SHA256_CTX& ctx, const unsigned char *data, _ntl_uint32 len) { _ntl_uint32 i; for (i=0; i < len; ++i) { ctx.data[ctx.datalen] = data[i]; ctx.datalen++; if (ctx.datalen == 64) { sha256_transform(ctx,ctx.data); DBL_INT_ADD(ctx.bitlen[0],ctx.bitlen[1],512); ctx.datalen = 0; } } } static void sha256_final(SHA256_CTX& ctx, unsigned char *hash, long hlen=SHA256_HASHSIZE) { _ntl_uint32 i, j; i = ctx.datalen; // Pad whatever data is left in the buffer. if (ctx.datalen < 56) { ctx.data[i++] = 0x80; while (i < 56) ctx.data[i++] = 0x00; } else { ctx.data[i++] = 0x80; while (i < 64) ctx.data[i++] = 0x00; sha256_transform(ctx,ctx.data); memset(ctx.data,0,56); } // Append to the padding the total message's length in bits and transform. DBL_INT_ADD(ctx.bitlen[0],ctx.bitlen[1],ctx.datalen * 8); ctx.data[63] = ctx.bitlen[0]; ctx.data[62] = ctx.bitlen[0] >> 8; ctx.data[61] = ctx.bitlen[0] >> 16; ctx.data[60] = ctx.bitlen[0] >> 24; ctx.data[59] = ctx.bitlen[1]; ctx.data[58] = ctx.bitlen[1] >> 8; ctx.data[57] = ctx.bitlen[1] >> 16; ctx.data[56] = ctx.bitlen[1] >> 24; sha256_transform(ctx,ctx.data); for (i = 0; i < 8; i++) { _ntl_uint32 w = ctx.state[i]; for (j = 0; j < 4; j++) { if (hlen <= 0) break; hash[4*i + j] = w >> (24-j*8); hlen--; } } } static void sha256(const unsigned char *data, long dlen, unsigned char *hash, long hlen=SHA256_HASHSIZE) { if (dlen < 0) dlen = 0; if (hlen < 0) hlen = 0; SHA256_CTX ctx; sha256_init(ctx); const long BLKSIZE = 4096; long i; for (i = 0; i <= dlen-BLKSIZE; i += BLKSIZE) sha256_update(ctx, data + i, BLKSIZE); if (i < dlen) sha256_update(ctx, data + i, dlen - i); sha256_final(ctx, hash, hlen); } static void hmac_sha256(const unsigned char *key, long klen, const unsigned char *data, long dlen, unsigned char *hash, long hlen=SHA256_HASHSIZE) { if (klen < 0) klen = 0; if (dlen < 0) dlen = 0; if (hlen < 0) hlen = 0; unsigned char K[SHA256_BLOCKSIZE]; unsigned char tmp[SHA256_HASHSIZE]; long i; if (klen <= SHA256_BLOCKSIZE) { for (i = 0; i < klen; i++) K[i] = key[i]; for (i = klen; i < SHA256_BLOCKSIZE; i++) K[i] = 0; } else { sha256(key, klen, K, SHA256_BLOCKSIZE); for (i = SHA256_HASHSIZE; i < SHA256_BLOCKSIZE; i++) K[i] = 0; } for (i = 0; i < SHA256_BLOCKSIZE; i++) K[i] ^= 0x36; SHA256_CTX ctx; sha256_init(ctx); sha256_update(ctx, K, SHA256_BLOCKSIZE); sha256_update(ctx, data, dlen); sha256_final(ctx, tmp); for (i = 0; i < SHA256_BLOCKSIZE; i++) K[i] ^= (0x36 ^ 0x5C); sha256_init(ctx); sha256_update(ctx, K, SHA256_BLOCKSIZE); sha256_update(ctx, tmp, SHA256_HASHSIZE); sha256_final(ctx, hash, hlen); } // This key derivation uses HMAC with a zero key to derive // an intermediate key K from the data, and then uses HMAC // as a PRF in counter mode with key K to derive the final key void DeriveKey(unsigned char *key, long klen, const unsigned char *data, long dlen) { if (dlen < 0) LogicError("DeriveKey: bad args"); if (klen < 0) LogicError("DeriveKey: bad args"); long i, j; unsigned char K[SHA256_HASHSIZE]; hmac_sha256(0, 0, data, dlen, K); // initialize 64-bit counter to zero unsigned char counter[8]; for (j = 0; j < 8; j++) counter[j] = 0; for (i = 0; i <= klen-SHA256_HASHSIZE; i += SHA256_HASHSIZE) { hmac_sha256(K, SHA256_HASHSIZE, counter, 8, key+i); // increment counter for (j = 0; j < 8; j++) { counter[j]++; if (counter[j] != 0) break; } } if (i < klen) hmac_sha256(K, SHA256_HASHSIZE, counter, 8, key+i, klen-i); } // ******************** ChaCha20 stuff *********************** // ============= old stuff #define LE(p) (((_ntl_uint32)((p)[0])) + ((_ntl_uint32)((p)[1]) << 8) + \ ((_ntl_uint32)((p)[2]) << 16) + ((_ntl_uint32)((p)[3]) << 24)) #define FROMLE(p, x) (p)[0] = (x), (p)[1] = ((x) >> 8), \ (p)[2] = ((x) >> 16), (p)[3] = ((x) >> 24) #define QUARTERROUND(x, a, b, c, d) \ x[a] += x[b], x[d] = ROTLEFT(x[d] ^ x[a], 16), \ x[c] += x[d], x[b] = ROTLEFT(x[b] ^ x[c], 12), \ x[a] += x[b], x[d] = ROTLEFT(x[d] ^ x[a], 8), \ x[c] += x[d], x[b] = ROTLEFT(x[b] ^ x[c], 7) static void salsa20_core(_ntl_uint32* data) { long i; for (i = 0; i < 10; i++) { QUARTERROUND(data, 0, 4, 8, 12); QUARTERROUND(data, 1, 5, 9, 13); QUARTERROUND(data, 2, 6, 10, 14); QUARTERROUND(data, 3, 7, 11, 15); QUARTERROUND(data, 0, 5, 10, 15); QUARTERROUND(data, 1, 6, 11, 12); QUARTERROUND(data, 2, 7, 8, 13); QUARTERROUND(data, 3, 4, 9, 14); } } // key K must be exactly 32 bytes static void salsa20_init(_ntl_uint32 *state, const unsigned char *K) { static const _ntl_uint32 chacha_const[4] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; long i; for (i = 0; i < 4; i++) state[i] = chacha_const[i]; for (i = 4; i < 12; i++) state[i] = LE(K + 4*(i-4)); for (i = 12; i < 16; i++) state[i] = 0; } // state and data are of length 16 static void salsa20_apply(_ntl_uint32 *state, _ntl_uint32 *data) { long i; for (i = 0; i < 16; i++) data[i] = state[i]; salsa20_core(data); for (i = 0; i < 16; i++) data[i] += state[i]; for (i = 12; i < 14; i++) { state[i]++; state[i] = INT32MASK(state[i]); if (state[i] != 0) break; } } old_RandomStream::old_RandomStream(const unsigned char *key) { salsa20_init(state, key); pos = 64; } void old_RandomStream::do_get(unsigned char *res, long n) { if (n < 0) LogicError("RandomStream::get: bad args"); long i, j; if (n <= 64-pos) { for (i = 0; i < n; i++) res[i] = buf[pos+i]; pos += n; return; } // read remainder of buffer for (i = 0; i < 64-pos; i++) res[i] = buf[pos+i]; n -= 64-pos; res += 64-pos; pos = 64; _ntl_uint32 wdata[16]; // read 64-byte chunks for (i = 0; i <= n-64; i += 64) { salsa20_apply(state, wdata); for (j = 0; j < 16; j++) FROMLE(res + i + 4*j, wdata[j]); } if (i < n) { salsa20_apply(state, wdata); for (j = 0; j < 16; j++) FROMLE(buf + 4*j, wdata[j]); pos = n-i; for (j = 0; j < pos; j++) res[i+j] = buf[j]; } } #if defined(NTL_RANDOM_AES256CTR) /* Size must be a multiple of AES block-size (16 bytes). */ #define BUFSIZE 4096 //#define BUFSIZE 8192 static void inc32(unsigned char ctr[16]) { int i, c = 1; for (i = 0; i < 4; i++) { c += ctr[15 - i]; ctr[15 - i] = (unsigned char)c; c >>= 8; } } #if defined(NTL_HAVE_AES_NI) && defined(NTL_HAVE_AVX2) /***************************************************************** This optimized AES-256 implementation is derived from public domain code. Authors: Romain Dolbeau Obtained from: https://github.com/floodyberry/supercop/blob/master/crypto_stream/aes256ctr/dolbeau/aesenc-int/aesenc-int.c */ #ifdef __INTEL_COMPILER #define ALIGN16 __declspec(align(16)) #define ALIGN32 __declspec(align(32)) #define ALIGN64 __declspec(align(64)) #else // assume GCC #define ALIGN16 __attribute__((aligned(16))) #define ALIGN32 __attribute__((aligned(32))) #define ALIGN64 __attribute__((aligned(64))) #ifndef _bswap64 #define _bswap64(a) __builtin_bswap64(a) #endif #ifndef _bswap #define _bswap(a) __builtin_bswap(a) #endif #endif static inline void aesni_key256_expand(const unsigned char* key, __m128i rkeys[16]) { __m128i key0 = _mm_loadu_si128((const __m128i *)(key+0)); __m128i key1 = _mm_loadu_si128((const __m128i *)(key+16)); __m128i temp0, temp1, temp2, temp4; int idx = 0; rkeys[idx++] = key0; temp0 = key0; temp2 = key1; /* blockshift-based block by Cedric Bourrasset & Romain Dolbeau */ #define BLOCK1(IMM) \ temp1 = _mm_aeskeygenassist_si128(temp2, IMM); \ rkeys[idx++] = temp2; \ temp4 = _mm_slli_si128(temp0,4); \ temp0 = _mm_xor_si128(temp0,temp4); \ temp4 = _mm_slli_si128(temp0,8); \ temp0 = _mm_xor_si128(temp0,temp4); \ temp1 = _mm_shuffle_epi32(temp1,0xff); \ temp0 = _mm_xor_si128(temp0,temp1) #define BLOCK2(IMM) \ temp1 = _mm_aeskeygenassist_si128(temp0, IMM); \ rkeys[idx++] = temp0; \ temp4 = _mm_slli_si128(temp2,4); \ temp2 = _mm_xor_si128(temp2,temp4); \ temp4 = _mm_slli_si128(temp2,8); \ temp2 = _mm_xor_si128(temp2,temp4); \ temp1 = _mm_shuffle_epi32(temp1,0xaa); \ temp2 = _mm_xor_si128(temp2,temp1) BLOCK1(0x01); BLOCK2(0x01); BLOCK1(0x02); BLOCK2(0x02); BLOCK1(0x04); BLOCK2(0x04); BLOCK1(0x08); BLOCK2(0x08); BLOCK1(0x10); BLOCK2(0x10); BLOCK1(0x20); BLOCK2(0x20); BLOCK1(0x40); rkeys[idx++] = temp0; } /** single, by-the-book AES encryption with AES-NI */ static inline void aesni_encrypt1(unsigned char *out, unsigned char *n, __m128i rkeys[16]) { __m128i nv = _mm_load_si128((const __m128i *)n); int i; __m128i temp = _mm_xor_si128(nv, rkeys[0]); #if 0 // This pragma is not recognized by GCC < 8 #pragma unroll(13) for (i = 1 ; i < 14 ; i++) { temp = _mm_aesenc_si128(temp, rkeys[i]); } #else temp = _mm_aesenc_si128(temp, rkeys[ 1]); temp = _mm_aesenc_si128(temp, rkeys[ 2]); temp = _mm_aesenc_si128(temp, rkeys[ 3]); temp = _mm_aesenc_si128(temp, rkeys[ 4]); temp = _mm_aesenc_si128(temp, rkeys[ 5]); temp = _mm_aesenc_si128(temp, rkeys[ 6]); temp = _mm_aesenc_si128(temp, rkeys[ 7]); temp = _mm_aesenc_si128(temp, rkeys[ 8]); temp = _mm_aesenc_si128(temp, rkeys[ 9]); temp = _mm_aesenc_si128(temp, rkeys[10]); temp = _mm_aesenc_si128(temp, rkeys[11]); temp = _mm_aesenc_si128(temp, rkeys[12]); temp = _mm_aesenc_si128(temp, rkeys[13]); #endif temp = _mm_aesenclast_si128(temp, rkeys[14]); _mm_store_si128((__m128i*)(out), temp); } /** increment the 16-bytes nonce ; this really should be improved somehow... but it's not yet time-critical, because we use the vector variant anyway */ static inline void incle(unsigned char n[16]) { /* unsigned long long out; */ /* unsigned char carry; */ unsigned long long *n_ = (unsigned long long*)n; n_[1]++; if (n_[1] == 0) n_[0] ++; /* perhaps this will be efficient on broadwell ? */ /* carry = _addcarry_u64(0, n_[1], 1ULL, &out); */ /* carry = _addcarry_u64(carry, n_[0], 0ULL, &out); */ } /** multiple-blocks-at-once AES encryption with AES-NI ; on Haswell, aesenc as a latency of 7 and a througput of 1 so the sequence of aesenc should be bubble-free, if you have at least 8 blocks. Let's build an arbitratry-sized function */ /* Step 1 : loading the nonce */ /* load & increment the n vector (non-vectorized, unused for now) */ #define NVx(a) \ __m128i nv##a = _mm_shuffle_epi8(_mm_load_si128((const __m128i *)n), _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)); incle(n) /* load the incremented n vector (vectorized, probably buggy) */ #define NVxV_DEC(a) \ __m128i nv##a; #define NVxV_NOWRAP(a) \ nv##a = _mm_shuffle_epi8(_mm_add_epi64(nv0i, _mm_set_epi64x(a,0)), _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)) #define NVxV_WRAP(a) \ __m128i ad##a = _mm_add_epi64(nv0i, _mm_set_epi64x(a,a>=wrapnumber?1:0)); \ nv##a = _mm_shuffle_epi8(ad##a, _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)) /* Step 2 : define value in round one (xor with subkey #0, aka key) */ #define TEMPx(a) \ __m128i temp##a = _mm_xor_si128(nv##a, rkeys[0]) /* Step 3: one round of AES */ #define AESENCx(a) \ temp##a = _mm_aesenc_si128(temp##a, rkeys[i]); /* Step 4: last round of AES */ #define AESENCLASTx(a) \ temp##a = _mm_aesenclast_si128(temp##a, rkeys[14]); /* Step 5: store result */ #define STOREx(a) \ _mm_store_si128((__m128i*)(out+(a*16)), temp##a); /* all the MAKE* macros are for automatic explicit unrolling */ #define MAKE4(X) \ X(0);X(1);X(2);X(3) #define MAKE6(X) \ X(0);X(1);X(2);X(3); \ X(4);X(5) #define MAKE7(X) \ X(0);X(1);X(2);X(3); \ X(4);X(5);X(6) #define MAKE8(X) \ X(0);X(1);X(2);X(3); \ X(4);X(5);X(6);X(7) #define MAKE10(X) \ X(0);X(1);X(2);X(3); \ X(4);X(5);X(6);X(7); \ X(8);X(9) #define MAKE12(X) \ X(0);X(1);X(2);X(3); \ X(4);X(5);X(6);X(7); \ X(8);X(9);X(10);X(11) #define MAKE16(X) \ X(0);X(1);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) /* create a function of unrolling N ; the MAKEN is the unrolling macro, defined above. The N in MAKEN must match N, obviously. */ #define FUNC(N, MAKEN) \ static inline void aesni_encrypt##N(unsigned char *out, unsigned char *n, __m128i rkeys[16]) { \ __m128i nv0i = _mm_load_si128((const __m128i *)n); \ long long nl = *(long long*)&n[8]; \ MAKEN(NVxV_DEC); \ /* check for nonce wraparound */ \ if ((nl < 0) && (nl + N) >= 0) { \ int wrapnumber = (int)(N - (nl+N)); \ MAKEN(NVxV_WRAP); \ _mm_storeu_si128((__m128i*)n, _mm_add_epi64(nv0i, _mm_set_epi64x(N,1))); \ } else { \ MAKEN(NVxV_NOWRAP); \ _mm_storeu_si128((__m128i*)n, _mm_add_epi64(nv0i, _mm_set_epi64x(N,0))); \ } \ int i; \ MAKEN(TEMPx); \ for (i = 1 ; i < 14 ; i++) { \ MAKEN(AESENCx); \ } \ MAKEN(AESENCLASTx); \ MAKEN(STOREx); \ } /* and now building our unrolled function is trivial */ FUNC(4, MAKE4) FUNC(6, MAKE6) FUNC(7, MAKE7) FUNC(8, MAKE8) FUNC(10, MAKE10) FUNC(12, MAKE12) FUNC(16, MAKE16) void crypto_stream( unsigned char *out, unsigned long long outlen, unsigned char *n, const unsigned char *k ) { __m128i rkeys[16]; ALIGN16 unsigned char n2[16]; unsigned long long i, j; aesni_key256_expand(k, rkeys); /* n2 is in byte-reversed (i.e., native little endian) order to make increment/testing easier */ (*(unsigned long long*)&n2[8]) = _bswap64((*(unsigned long long*)&n[8])); (*(unsigned long long*)&n2[0]) = _bswap64((*(unsigned long long*)&n[0])); #define LOOP(iter) \ int lb = iter * 16; \ for (i = 0 ; i < outlen ; i+= lb) { \ ALIGN16 unsigned char outni[lb]; \ aesni_encrypt##iter(outni, n2, rkeys); \ unsigned long long mj = lb; \ if ((i+mj)>=outlen) \ mj = outlen-i; \ for (j = 0 ; j < mj ; j++) \ out[i+j] = outni[j]; \ } LOOP(8); (*(unsigned long long*)&n[8]) = _bswap64((*(unsigned long long*)&n2[8])); (*(unsigned long long*)&n[0]) = _bswap64((*(unsigned long long*)&n2[0])); } static void aes256ctr_stream(unsigned char out[BUFSIZE], unsigned char iv[16], const unsigned char key[32]) { crypto_stream(out, BUFSIZE, iv, key); } /*****************************************************************/ #elif defined(NTL_HAVE_KMA) static void aes256ctr_stream(unsigned char out[BUFSIZE], unsigned char iv[16], const unsigned char key[32]) { static const unsigned char zerobuf[BUFSIZE] = {0}; unsigned long fc = CPACF_KMA_GCM_AES_256 | CPACF_KMA_HS | CPACF_KMA_LAAD; struct { unsigned char reserved[12]; unsigned int cv; unsigned char _[48]; unsigned char j0[16]; unsigned char k[32]; } param; memcpy(¶m.cv, &iv[12], sizeof(param.cv)); param.cv--; memcpy(¶m.j0[0], &iv[0], sizeof(param.j0) - sizeof(param.cv)); memcpy(¶m.j0[12], ¶m.cv, sizeof(param.cv)); memcpy(param.k, key, sizeof(param.k)); cpacf_kma(fc, ¶m, out, NULL, 0, zerobuf, sizeof(zerobuf)); param.cv++; memcpy(&iv[12], ¶m.cv, sizeof(param.cv)); } #else /***************************************************************** This AES-256 reference implementation is derived from public domain code. Authors: Vincent Rijmen Antoon Bosselaers Paulo Barreto Obtained from: https://github.com/zakird/zdlibc/blob/master/rijndael-alg-fst.c */ typedef uint8_t u8; typedef uint32_t u32; static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, }; #define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) #ifdef _MSC_VER #define GETU32(p) SWAP(*((u32 *)(p))) #define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } #else #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } #endif /** * Expand the cipher key into the encryption key schedule. */ void AES256KeySetupEnc(u32 rk[60], const u8 cipherKey[32]) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) return; temp = rk[11]; rk[12] = rk[ 4] ^ (Te4[(temp >> 24) ] & 0xff000000) ^ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(temp ) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } void AES256Encrypt(const u32 rk[60], const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; int r, Nr = 14; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) break; s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24) ] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct , s0); s1 = (Te4[(t1 >> 24) ] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } /*****************************************************************/ static void aes256ctr_stream(unsigned char out[BUFSIZE], unsigned char iv[16], const unsigned char key[32]) { u32 rk[60]; int i; AES256KeySetupEnc(rk, key); for (i = 0; i < BUFSIZE; i += 16) { AES256Encrypt(rk, iv, out + i); inc32(iv); } } #endif struct RandomStream_impl { unsigned char key[32]; unsigned char iv[16]; unsigned char buf[BUFSIZE]; explicit RandomStream_impl(const unsigned char *k) { memcpy(key, k, sizeof(key)); memset(iv, 0, sizeof(iv)); iv[15] = 1; // nonce = 1 } const unsigned char * get_buf() const { return buf + sizeof(key); } long get_buf_len() const { return sizeof(buf) - sizeof(key); } long get_bytes(unsigned char *res, long n, long pos) { size_t len; if (n < 0) LogicError("RandomStream::get: bad args"); if (n > 0 && sizeof(buf) - sizeof(key) - pos > 0) { len = min((size_t)n, sizeof(buf) - sizeof(key) - pos); memcpy(res, buf + sizeof(key) + pos, len); n -= len; res += len; pos += len; } while (n > 0) { aes256ctr_stream(buf, iv, key); memcpy(key, buf, sizeof(key)); len = min((size_t)n, sizeof(buf) - sizeof(key)); memcpy(res, buf + sizeof(key), len); n -= len; res += len; pos = len; } return pos; } void set_nonce(unsigned long nonce) { // low-order 8 bytes of iv set to zero // high-order 8 bytes of iv set to nonce memset(iv, 0, sizeof(iv)); iv[ 8] = (unsigned char) nonce; nonce >>= 8; iv[ 9] = (unsigned char) nonce; nonce >>= 8; iv[10] = (unsigned char) nonce; nonce >>= 8; iv[11] = (unsigned char) nonce; nonce >>= 8; iv[12] = (unsigned char) nonce; nonce >>= 8; iv[13] = (unsigned char) nonce; nonce >>= 8; iv[14] = (unsigned char) nonce; nonce >>= 8; iv[15] = (unsigned char) nonce; nonce >>= 8; } }; #else // defined(NTL_RANDOM_AES256CTR) #if (defined(NTL_HAVE_AVX2) || defined(NTL_HAVE_SSSE3)) /***************************************************************** This AVX2 implementation is derived from public domain code originally developed by Martin Goll Shay Gueron, and obtained from here: https://github.com/floodyberry/supercop/tree/master/crypto_stream/chacha20/goll_gueron On a Haswell machine, ths code is about 4.x faster than the vanilla C code. The following is the README from that page ================================================================== This code implements Daniel J. Bernstein's ChaCha stream cipher in C, targeting architectures with AVX2 and future AVX512 vector extensions. The implementation improves the slightly modified implementations of Ted Krovetz in the Chromium Project (http://src.chromium.org/viewvc/chrome/trunk/deps/third_party/nss/nss/lib/freebl/chacha20/chacha20_vec.c and http://src.chromium.org/viewvc/chrome/trunk/deps/third_party/openssl/openssl/crypto/chacha/chacha_vec.c) by using the Advanced Vector Extensions AVX2 and, if available in future, AVX512 to widen the vectorization to 256-bit, respectively 512-bit. On Intel's Haswell architecture this implementation (using AVX2) is almost ~2x faster than the fastest implementation here, when encrypting (decrypting) 2 blocks and more. Also, this implementation is expected to double the speed again, when encrypting (decrypting) 4 blocks and more, running on a future architecture with support for AVX512. Further details and our measurement results are provided in: Goll, M., and Gueron,S.: Vectorization of ChaCha Stream Cipher. Cryptology ePrint Archive, Report 2013/759, November, 2013, http://eprint.iacr.org/2013/759.pdf Developers and authors: ********************************************************* Martin Goll (1) and Shay Gueron (2, 3), (1) Ruhr-University Bochum, Germany (2) University of Haifa, Israel (3) Intel Corporation, Israel Development Center, Haifa, Israel ********************************************************* Intellectual Property Notices ----------------------------- There are no known present or future claims by a copyright holder that the distribution of this software infringes the copyright. In particular, the author of the software is not making such claims and does not intend to make such claims. There are no known present or future claims by a patent holder that the use of this software infringes the patent. In particular, the author of the software is not making such claims and does not intend to make such claims. Our implementation is in public domain. *****************************************************************/ // round selector, specified values: // 8: low security - high speed // 12: mid security - mid speed // 20: high security - low speed #ifndef CHACHA_RNDS #define CHACHA_RNDS 20 #endif #if (defined(NTL_HAVE_AVX2)) typedef __m256i ivec_t; #define DELTA _mm256_set_epi64x(0,2,0,2) #define START _mm256_set_epi64x(0,1,0,0) #define NONCE(nonce) _mm256_set_epi64x(nonce, 1, nonce, 0) #define STOREU_VEC(m,r) _mm256_storeu_si256((__m256i*)(m), r) #define STORE_VEC(m,r) _mm256_store_si256((__m256i*)(m), r) #define LOAD_VEC(r,m) r = _mm256_load_si256((const __m256i *)(m)) #define LOADU_VEC(r,m) r = _mm256_loadu_si256((const __m256i *)(m)) #define LOADU_VEC_128(r, m) r = _mm256_broadcastsi128_si256(_mm_loadu_si128((const __m128i*)(m))) #define ADD_VEC_32(a,b) _mm256_add_epi32(a, b) #define ADD_VEC_64(a,b) _mm256_add_epi64(a, b) #define XOR_VEC(a,b) _mm256_xor_si256(a, b) #define ROR_VEC_V1(x) _mm256_shuffle_epi32(x,_MM_SHUFFLE(0,3,2,1)) #define ROR_VEC_V2(x) _mm256_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2)) #define ROR_VEC_V3(x) _mm256_shuffle_epi32(x,_MM_SHUFFLE(2,1,0,3)) #define ROL_VEC_7(x) XOR_VEC(_mm256_slli_epi32(x, 7), _mm256_srli_epi32(x,25)) #define ROL_VEC_12(x) XOR_VEC(_mm256_slli_epi32(x,12), _mm256_srli_epi32(x,20)) #define ROL_VEC_8(x) _mm256_shuffle_epi8(x,_mm256_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3,14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3)) #define ROL_VEC_16(x) _mm256_shuffle_epi8(x,_mm256_set_epi8(13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2,13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2)) #define WRITEU_VEC(op, d, v0, v1, v2, v3) \ STOREU_VEC(op + (d + 0*4), _mm256_permute2x128_si256(v0, v1, 0x20)); \ STOREU_VEC(op + (d + 8*4), _mm256_permute2x128_si256(v2, v3, 0x20)); \ STOREU_VEC(op + (d +16*4), _mm256_permute2x128_si256(v0, v1, 0x31)); \ STOREU_VEC(op + (d +24*4), _mm256_permute2x128_si256(v2, v3, 0x31)); #define WRITE_VEC(op, d, v0, v1, v2, v3) \ STORE_VEC(op + (d + 0*4), _mm256_permute2x128_si256(v0, v1, 0x20)); \ STORE_VEC(op + (d + 8*4), _mm256_permute2x128_si256(v2, v3, 0x20)); \ STORE_VEC(op + (d +16*4), _mm256_permute2x128_si256(v0, v1, 0x31)); \ STORE_VEC(op + (d +24*4), _mm256_permute2x128_si256(v2, v3, 0x31)); #define SZ_VEC (32) #define RANSTREAM_NCHUNKS (2) // leads to a BUFSZ of 512 #elif defined(NTL_HAVE_SSSE3) typedef __m128i ivec_t; #define DELTA _mm_set_epi32(0,0,0,1) #define START _mm_setzero_si128() #define NONCE(nonce) _mm_set_epi64x(nonce,0) #define STOREU_VEC(m,r) _mm_storeu_si128((__m128i*)(m), r) #define STORE_VEC(m,r) _mm_store_si128((__m128i*)(m), r) #define LOAD_VEC(r,m) r = _mm_load_si128((const __m128i *)(m)) #define LOADU_VEC(r,m) r = _mm_loadu_si128((const __m128i *)(m)) #define LOADU_VEC_128(r, m) r = _mm_loadu_si128((const __m128i*)(m)) #define ADD_VEC_32(a,b) _mm_add_epi32(a, b) #define ADD_VEC_64(a,b) _mm_add_epi64(a, b) #define XOR_VEC(a,b) _mm_xor_si128(a, b) #define ROR_VEC_V1(x) _mm_shuffle_epi32(x,_MM_SHUFFLE(0,3,2,1)) #define ROR_VEC_V2(x) _mm_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2)) #define ROR_VEC_V3(x) _mm_shuffle_epi32(x,_MM_SHUFFLE(2,1,0,3)) #define ROL_VEC_7(x) XOR_VEC(_mm_slli_epi32(x, 7), _mm_srli_epi32(x,25)) #define ROL_VEC_12(x) XOR_VEC(_mm_slli_epi32(x,12), _mm_srli_epi32(x,20)) #define ROL_VEC_8(x) _mm_shuffle_epi8(x,_mm_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3)) #define ROL_VEC_16(x) _mm_shuffle_epi8(x,_mm_set_epi8(13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2)) #define WRITEU_VEC(op, d, v0, v1, v2, v3) \ STOREU_VEC(op + (d + 0*4), v0); \ STOREU_VEC(op + (d + 4*4), v1); \ STOREU_VEC(op + (d + 8*4), v2); \ STOREU_VEC(op + (d +12*4), v3); #define WRITE_VEC(op, d, v0, v1, v2, v3) \ STORE_VEC(op + (d + 0*4), v0); \ STORE_VEC(op + (d + 4*4), v1); \ STORE_VEC(op + (d + 8*4), v2); \ STORE_VEC(op + (d +12*4), v3); #define SZ_VEC (16) #define RANSTREAM_NCHUNKS (4) // leads to a BUFSZ of 512 #else #error "unsupported architecture" #endif #define DQROUND_VECTORS_VEC(a,b,c,d) \ a = ADD_VEC_32(a,b); d = XOR_VEC(d,a); d = ROL_VEC_16(d); \ c = ADD_VEC_32(c,d); b = XOR_VEC(b,c); b = ROL_VEC_12(b); \ a = ADD_VEC_32(a,b); d = XOR_VEC(d,a); d = ROL_VEC_8(d); \ c = ADD_VEC_32(c,d); b = XOR_VEC(b,c); b = ROL_VEC_7(b); \ b = ROR_VEC_V1(b); c = ROR_VEC_V2(c); d = ROR_VEC_V3(d); \ a = ADD_VEC_32(a,b); d = XOR_VEC(d,a); d = ROL_VEC_16(d); \ c = ADD_VEC_32(c,d); b = XOR_VEC(b,c); b = ROL_VEC_12(b); \ a = ADD_VEC_32(a,b); d = XOR_VEC(d,a); d = ROL_VEC_8(d); \ c = ADD_VEC_32(c,d); b = XOR_VEC(b,c); b = ROL_VEC_7(b); \ b = ROR_VEC_V3(b); c = ROR_VEC_V2(c); d = ROR_VEC_V1(d); #define RANSTREAM_STATESZ (4*SZ_VEC) #define RANSTREAM_CHUNKSZ (2*RANSTREAM_STATESZ) #define RANSTREAM_BUFSZ (RANSTREAM_NCHUNKS*RANSTREAM_CHUNKSZ) struct RandomStream_impl { AlignedArray state_store; AlignedArray buf_store; long chunk_count; void allocate_space() { state_store.SetLength(RANSTREAM_STATESZ); buf_store.SetLength(RANSTREAM_BUFSZ); } explicit RandomStream_impl(const unsigned char *key) { allocate_space(); unsigned char *state = state_store.elts(); unsigned int chacha_const[] = { 0x61707865,0x3320646E,0x79622D32,0x6B206574 }; ivec_t d0, d1, d2, d3; LOADU_VEC_128(d0, chacha_const); LOADU_VEC_128(d1, key); LOADU_VEC_128(d2, key+16); d3 = START; STORE_VEC(state + 0*SZ_VEC, d0); STORE_VEC(state + 1*SZ_VEC, d1); STORE_VEC(state + 2*SZ_VEC, d2); STORE_VEC(state + 3*SZ_VEC, d3); chunk_count = 0; } RandomStream_impl(const RandomStream_impl& other) { allocate_space(); *this = other; } RandomStream_impl& operator=(const RandomStream_impl& other) { std::memcpy(state_store.elts(), other.state_store.elts(), RANSTREAM_STATESZ); std::memcpy(buf_store.elts(), other.buf_store.elts(), RANSTREAM_BUFSZ); chunk_count = other.chunk_count; return *this; } const unsigned char * get_buf() const { return buf_store.elts(); } long get_buf_len() const { return RANSTREAM_BUFSZ; } // bytes are generated in chunks of RANSTREAM_BUFSZ bytes, except that // initially, we may generate a few chunks of RANSTREAM_CHUNKSZ // bytes. This optimizes a bit for short bursts following a reset. long get_bytes(unsigned char *NTL_RESTRICT res, long n, long pos) { if (n < 0) LogicError("RandomStream::get: bad args"); if (n == 0) return pos; unsigned char *NTL_RESTRICT buf = buf_store.elts(); if (n <= RANSTREAM_BUFSZ-pos) { std::memcpy(&res[0], &buf[pos], n); pos += n; return pos; } unsigned char *NTL_RESTRICT state = state_store.elts(); ivec_t d0, d1, d2, d3; LOAD_VEC(d0, state + 0*SZ_VEC); LOAD_VEC(d1, state + 1*SZ_VEC); LOAD_VEC(d2, state + 2*SZ_VEC); LOAD_VEC(d3, state + 3*SZ_VEC); // read remainder of buffer std::memcpy(&res[0], &buf[pos], RANSTREAM_BUFSZ-pos); n -= RANSTREAM_BUFSZ-pos; res += RANSTREAM_BUFSZ-pos; pos = RANSTREAM_BUFSZ; long i = 0; for (; i <= n-RANSTREAM_BUFSZ; i += RANSTREAM_BUFSZ) { chunk_count |= RANSTREAM_NCHUNKS; // disable small buffer strategy for (long j = 0; j < RANSTREAM_NCHUNKS; j++) { ivec_t v0=d0, v1=d1, v2=d2, v3=d3; ivec_t v4=d0, v5=d1, v6=d2, v7=ADD_VEC_64(d3, DELTA); for (long k = 0; k < CHACHA_RNDS/2; k++) { DQROUND_VECTORS_VEC(v0,v1,v2,v3) DQROUND_VECTORS_VEC(v4,v5,v6,v7) } WRITEU_VEC(res+i+j*(8*SZ_VEC), 0, ADD_VEC_32(v0,d0), ADD_VEC_32(v1,d1), ADD_VEC_32(v2,d2), ADD_VEC_32(v3,d3)) d3 = ADD_VEC_64(d3, DELTA); WRITEU_VEC(res+i+j*(8*SZ_VEC), 4*SZ_VEC, ADD_VEC_32(v4,d0), ADD_VEC_32(v5,d1), ADD_VEC_32(v6,d2), ADD_VEC_32(v7,d3)) d3 = ADD_VEC_64(d3, DELTA); } } if (i < n) { long nchunks; if (chunk_count < RANSTREAM_NCHUNKS) { nchunks = long(cast_unsigned((n-i)+RANSTREAM_CHUNKSZ-1)/RANSTREAM_CHUNKSZ); chunk_count += nchunks; } else nchunks = RANSTREAM_NCHUNKS; long pos_offset = RANSTREAM_BUFSZ - nchunks*RANSTREAM_CHUNKSZ; buf += pos_offset; for (long j = 0; j < nchunks; j++) { ivec_t v0=d0, v1=d1, v2=d2, v3=d3; ivec_t v4=d0, v5=d1, v6=d2, v7=ADD_VEC_64(d3, DELTA); for (long k = 0; k < CHACHA_RNDS/2; k++) { DQROUND_VECTORS_VEC(v0,v1,v2,v3) DQROUND_VECTORS_VEC(v4,v5,v6,v7) } WRITE_VEC(buf+j*(8*SZ_VEC), 0, ADD_VEC_32(v0,d0), ADD_VEC_32(v1,d1), ADD_VEC_32(v2,d2), ADD_VEC_32(v3,d3)) d3 = ADD_VEC_64(d3, DELTA); WRITE_VEC(buf+j*(8*SZ_VEC), 4*SZ_VEC, ADD_VEC_32(v4,d0), ADD_VEC_32(v5,d1), ADD_VEC_32(v6,d2), ADD_VEC_32(v7,d3)) d3 = ADD_VEC_64(d3, DELTA); } pos = n-i+pos_offset; std::memcpy(&res[i], &buf[0], n-i); } STORE_VEC(state + 3*SZ_VEC, d3); return pos; } void set_nonce(unsigned long nonce) { unsigned char *state = state_store.elts(); ivec_t d3; d3 = NONCE(nonce); STORE_VEC(state + 3*SZ_VEC, d3); chunk_count = 0; } }; #else struct RandomStream_impl { _ntl_uint32 state[16]; unsigned char buf[64]; explicit RandomStream_impl(const unsigned char *key) { salsa20_init(state, key); } const unsigned char * get_buf() const { return &buf[0]; } long get_buf_len() const { return 64; } long get_bytes(unsigned char *res, long n, long pos) { if (n < 0) LogicError("RandomStream::get: bad args"); long i, j; if (n <= 64-pos) { for (i = 0; i < n; i++) res[i] = buf[pos+i]; pos += n; return pos; } // read remainder of buffer for (i = 0; i < 64-pos; i++) res[i] = buf[pos+i]; n -= 64-pos; res += 64-pos; pos = 64; _ntl_uint32 wdata[16]; // read 64-byte chunks for (i = 0; i <= n-64; i += 64) { salsa20_apply(state, wdata); for (j = 0; j < 16; j++) FROMLE(res + i + 4*j, wdata[j]); } if (i < n) { salsa20_apply(state, wdata); for (j = 0; j < 16; j++) FROMLE(buf + 4*j, wdata[j]); pos = n-i; for (j = 0; j < pos; j++) res[i+j] = buf[j]; } return pos; } void set_nonce(unsigned long nonce) { _ntl_uint32 nonce0, nonce1; nonce0 = nonce; nonce0 = INT32MASK(nonce0); nonce1 = 0; #if (NTL_BITS_PER_LONG > 32) nonce1 = nonce >> 32; nonce1 = INT32MASK(nonce1); #endif state[12] = 0; state[13] = 0; state[14] = nonce0; state[15] = nonce1; } }; #endif #endif // defined(NTL_RANDOMSTREAM_AES256CTR) // Boilerplate PIMPL code RandomStream_impl * RandomStream_impl_build(const unsigned char *key) { UniquePtr p; p.make(key); return p.release(); } RandomStream_impl * RandomStream_impl_build(const RandomStream_impl& other) { UniquePtr p; p.make(other); return p.release(); } void RandomStream_impl_copy(RandomStream_impl& x, const RandomStream_impl& y) { x = y; } void RandomStream_impl_delete(RandomStream_impl* p) { delete p; } const unsigned char * RandomStream_impl_get_buf(const RandomStream_impl& x) { return x.get_buf(); } long RandomStream_impl_get_buf_len(const RandomStream_impl& x) { return x.get_buf_len(); } long RandomStream_impl_get_bytes(RandomStream_impl& impl, unsigned char *res, long n, long pos) { return impl.get_bytes(res, n, pos); } void RandomStream_impl_set_nonce(RandomStream_impl& impl, unsigned long nonce) { impl.set_nonce(nonce); } NTL_TLS_GLOBAL_DECL(UniquePtr, CurrentRandomStream); void SetSeed(const RandomStream& s) { NTL_TLS_GLOBAL_ACCESS(CurrentRandomStream); if (!CurrentRandomStream) CurrentRandomStream.make(s); else *CurrentRandomStream = s; } void SetSeed(const unsigned char *data, long dlen) { if (dlen < 0) LogicError("SetSeed: bad args"); Vec key; key.SetLength(NTL_PRG_KEYLEN); DeriveKey(key.elts(), NTL_PRG_KEYLEN, data, dlen); SetSeed(RandomStream(key.elts())); } void SetSeed(const ZZ& seed) { long nb = NumBytes(seed); Vec buf; buf.SetLength(nb); BytesFromZZ(buf.elts(), seed, nb); SetSeed(buf.elts(), nb); } static void InitRandomStream() { const std::string& id = UniqueID(); SetSeed((const unsigned char *) id.c_str(), id.length()); } static inline RandomStream& LocalGetCurrentRandomStream() { NTL_TLS_GLOBAL_ACCESS(CurrentRandomStream); if (!CurrentRandomStream) InitRandomStream(); return *CurrentRandomStream; } RandomStream& GetCurrentRandomStream() { return LocalGetCurrentRandomStream(); } static inline unsigned long WordFromBytes(const unsigned char *buf, long n) { unsigned long res = 0; long i; for (i = n-1; i >= 0; i--) res = (res << 8) | buf[i]; return res; } unsigned long RandomWord() { RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; stream.get(buf, NTL_BITS_PER_LONG/8); return WordFromBytes(buf, NTL_BITS_PER_LONG/8); } void VectorRandomWord(long k, unsigned long* x) { RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; for (long i = 0; i < k; i++) { stream.get(buf, NTL_BITS_PER_LONG/8); x[i] = WordFromBytes(buf, NTL_BITS_PER_LONG/8); } } long RandomBits_long(long l) { if (l <= 0) return 0; if (l >= NTL_BITS_PER_LONG) ResourceError("RandomBits: length too big"); RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; long nb = (l+7)/8; stream.get(buf, nb); return long(WordFromBytes(buf, nb) & ((1UL << l)-1UL)); } unsigned long RandomBits_ulong(long l) { if (l <= 0) return 0; if (l > NTL_BITS_PER_LONG) ResourceError("RandomBits: length too big"); RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; long nb = (l+7)/8; stream.get(buf, nb); unsigned long res = WordFromBytes(buf, nb); if (l < NTL_BITS_PER_LONG) res = res & ((1UL << l)-1UL); return res; } long RandomLen_long(long l) { if (l <= 0) return 0; if (l == 1) return 1; if (l >= NTL_BITS_PER_LONG) ResourceError("RandomLen: length too big"); RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; long nb = ((l-1)+7)/8; stream.get(buf, nb); unsigned long res = WordFromBytes(buf, nb); unsigned long mask = (1UL << (l-1)) - 1UL; return long((res & mask) | (mask+1UL)); } long RandomBnd(long bnd) { if (bnd <= 1) return 0; RandomStream& stream = LocalGetCurrentRandomStream(); unsigned char buf[NTL_BITS_PER_LONG/8]; long l = NumBits(bnd-1); long nb = (l+7)/8; long tmp; do { stream.get(buf, nb); tmp = long(WordFromBytes(buf, nb) & ((1UL << l)-1UL)); } while (tmp >= bnd); return tmp; } void RandomBits(ZZ& x, long l) { if (l <= 0) { x = 0; return; } if (NTL_OVERFLOW(l, 1, 0)) ResourceError("RandomBits: length too big"); RandomStream& stream = LocalGetCurrentRandomStream(); long nb = (l+7)/8; unsigned long mask = (1UL << (8 - nb*8 + l)) - 1UL; NTL_TLS_LOCAL(Vec, buf_mem); Vec::Watcher watch_buf_mem(buf_mem); buf_mem.SetLength(nb); unsigned char *buf = buf_mem.elts(); x.SetSize((l + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS); // pre-allocate to ensure strong ES stream.get(buf, nb); buf[nb-1] &= mask; ZZFromBytes(x, buf, nb); } void RandomLen(ZZ& x, long l) { if (l <= 0) { x = 0; return; } if (l == 1) { x = 1; return; } if (NTL_OVERFLOW(l, 1, 0)) ResourceError("RandomLen: length too big"); RandomStream& stream = LocalGetCurrentRandomStream(); long nb = (l+7)/8; unsigned long mask = (1UL << (8 - nb*8 + l)) - 1UL; NTL_TLS_LOCAL(Vec, buf_mem); Vec::Watcher watch_buf_mem(buf_mem); buf_mem.SetLength(nb); unsigned char *buf = buf_mem.elts(); x.SetSize((l + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS); // pre-allocate to ensure strong ES stream.get(buf, nb); buf[nb-1] &= mask; buf[nb-1] |= ((mask >> 1) + 1UL); ZZFromBytes(x, buf, nb); } /********************************************************** The following implementation of RandomBnd is designed for speed. It certainly is not resilient against a timing side-channel attack (but then again, none of these PRG routines are designed to be). The naive strategy generates random candidates of the right bit length until the candidate < bnd. The idea in this implementation is to generate the high order two bytes of the candidate first, and compare this to the high order two bytes of tmp. We can discard the candidate if this is already too large. ***********************************************************/ void RandomBnd(ZZ& x, const ZZ& bnd) { if (bnd <= 1) { x = 0; return; } RandomStream& stream = LocalGetCurrentRandomStream(); long l = NumBits(bnd); long nb = (l+7)/8; if (nb <= 3) { long lbnd = conv(bnd); unsigned char lbuf[3]; long ltmp; x.SetSize((l + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS); // pre-allocate to ensure strong ES do { stream.get(lbuf, nb); ltmp = long(WordFromBytes(lbuf, nb) & ((1UL << l)-1UL)); } while (ltmp >= lbnd); conv(x, ltmp); return; } // deal with possible alias NTL_ZZRegister(tmp_store); const ZZ& bnd_ref = ((&x == &bnd) ? (tmp_store = bnd) : bnd); NTL_ZZRegister(hbnd); RightShift(hbnd, bnd_ref, (nb-2)*8); long lhbnd = conv(hbnd); unsigned long mask = (1UL << (16 - nb*8 + l)) - 1UL; NTL_TLS_LOCAL(Vec, buf_mem); Vec::Watcher watch_buf_mem(buf_mem); buf_mem.SetLength(nb); unsigned char *buf = buf_mem.elts(); unsigned char hbuf[2]; x.SetSize((l + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS); // pre-allocate to ensure strong ES for (;;) { stream.get(hbuf, 2); long hpart = long(WordFromBytes(hbuf, 2) & mask); if (hpart > lhbnd) continue; stream.get(buf, nb-2); buf[nb-2] = ((unsigned long) hpart); buf[nb-1] = ((unsigned long) hpart) >> 8; ZZFromBytes(x, buf, nb); if (hpart < lhbnd || x < bnd_ref) break; } } // More prime generation stuff... static double Log2(double x) { static const double log2 = log(2.0); // GLOBAL (relies on C++11 thread-safe init) return log(x)/log2; } // Define p(k,t) to be the conditional probability that a random, odd, k-bit // number is composite, given that it passes t iterations of the // Miller-Rabin test. // If this routine returns a non-zero value, then // p(k,t) <= 2^{-n}. // This basically encodes the estimates of Damgard, Landrock, and Pomerance; // it uses floating point arithmetic, but is coded in such a way // that its results should be correct, assuming that the log function // is computed with reasonable precision. // // It is assumed that k >= 3 and t >= 1; if this does not hold, // then 0 is returned. static long ErrBoundTest(long kk, long tt, long nn) { const double fudge = (1.0 + 1024.0/NTL_FDOUBLE_PRECISION); const double log2_3 = Log2(3.0); const double log2_7 = Log2(7.0); const double log2_20 = Log2(20.0); double k = kk; double t = tt; double n = nn; if (k < 3 || t < 1) return 0; if (n < 1) return 1; // the following test is largely academic if (9*t > NTL_FDOUBLE_PRECISION) LogicError("ErrBoundTest: t too big"); double log2_k = Log2(k); if ((n + log2_k)*fudge <= 2*t) return 1; if ((2*log2_k + 4.0 + n)*fudge <= 2*sqrt(k)) return 2; if ((t == 2 && k >= 88) || (3 <= t && 9*t <= k && k >= 21)) { if ((1.5*log2_k + t + 4.0 + n)*fudge <= 0.5*Log2(t) + 2*(sqrt(t*k))) return 3; } if (k <= 9*t && 4*t <= k && k >= 21) { if ( ((log2_3 + log2_7 + log2_k + n)*fudge <= log2_20 + 5*t) && ((log2_3 + (15.0/4.0)*log2_k + n)*fudge <= log2_7 + k/2 + 2*t) && ((2*log2_3 + 2 + log2_k + n)*fudge <= k/4 + 3*t) ) return 4; } if (4*t >= k && k >= 21) { if (((15.0/4.0)*log2_k + n)*fudge <= log2_7 + k/2 + 2*t) return 5; } return 0; } void GenPrime(ZZ& n, long k, long err) { if (k <= 1) LogicError("GenPrime: bad length"); if (k > (1L << 20)) ResourceError("GenPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } long t; t = 1; while (!ErrBoundTest(k, t, err)) t++; RandomPrime(n, k, t); } long GenPrime_long(long k, long err) { if (k <= 1) LogicError("GenPrime: bad length"); if (k >= NTL_BITS_PER_LONG) ResourceError("GenPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) return 3; else return 2; } long t; t = 1; while (!ErrBoundTest(k, t, err)) t++; return RandomPrime_long(k, t); } void MultiThreadedGenGermainPrime(ZZ& n, long k, long err) { long nt = AvailableThreads(); long prime_bnd = ComputePrimeBound(k); if (NumBits(prime_bnd) >= k/2) prime_bnd = (1L << (k/2-1)); ZZ two; two = 2; const long LOCAL_ITER_BOUND = 8; // since resetting the PRG comes at a certain cost, // we perform a few iterations with each reset to // amortize the reset cost. unsigned long initial_counter = 0; ZZ seed; RandomBits(seed, 256); ZZ overflow_counter; for (;;) { AtomicLowWaterMark low_water_mark(-1UL); AtomicCounter counter(initial_counter); Vec< UniquePtr > result(INIT_SIZE, nt); Vec result_ctr(INIT_SIZE, nt, -1UL); NTL_EXEC_INDEX(nt, index) RandomStreamPush push; SetSeed(seed); RandomStream& stream = GetCurrentRandomStream(); ZZ cand, n1; PrimeSeq s; while (low_water_mark == -1UL) { unsigned long local_ctr = counter.inc(); if (local_ctr >> (NTL_BITS_PER_NONCE-1)) { // counter overflow...rather academic break; } stream.set_nonce(local_ctr); for (long iter = 0; iter < LOCAL_ITER_BOUND && local_ctr <= low_water_mark; iter++) { RandomLen(cand, k); if (!IsOdd(cand)) add(cand, cand, 1); s.reset(3); long p; long sieve_passed = 1; p = s.next(); while (p && p < prime_bnd) { long r = rem(cand, p); if (r == 0) { sieve_passed = 0; break; } // test if 2*r + 1 = 0 (mod p) if (r == p-r-1) { sieve_passed = 0; break; } p = s.next(); } if (!sieve_passed) continue; if (MillerWitness(cand, two)) continue; // n1 = 2*cand+1 mul(n1, cand, 2); add(n1, n1, 1); if (MillerWitness(n1, two)) continue; result[index].make(cand); result_ctr[index] = local_ctr; low_water_mark.UpdateMin(local_ctr); break; } } NTL_EXEC_INDEX_END // find index of low_water_mark unsigned long low_water_mark1 = low_water_mark; long low_water_index = -1; for (long index = 0; index < nt; index++) { if (result_ctr[index] == low_water_mark1) { low_water_index = index; break; } } if (low_water_index == -1) { // counter overflow...rather academic overflow_counter++; initial_counter = 0; RandomBits(seed, 256); continue; } ZZ N; N = *result[low_water_index]; ZZ iter = ((overflow_counter << (NTL_BITS_PER_NONCE-1)) + conv(low_water_mark1) + 1)*LOCAL_ITER_BOUND; // now do t M-R iterations...just to make sure // First compute the appropriate number of M-R iterations, t // The following computes t such that // p(k,t)*8/k <= 2^{-err}/(5*iter^{1.25}) // which suffices to get an overall error probability of 2^{-err}. // Note that this method has the advantage of not requiring // any assumptions on the density of Germain primes. long err1 = max(1, err + 7 + (5*NumBits(iter) + 3)/4 - NumBits(k)); long t; t = 1; while (!ErrBoundTest(k, t, err1)) t++; Vec W(INIT_SIZE, t); for (long i = 0; i < t; i++) { do { RandomBnd(W[i], N); } while (W[i] == 0); } AtomicBool tests_pass(true); NTL_EXEC_RANGE(t, first, last) for (long i = first; i < last && tests_pass; i++) { if (MillerWitness(N, W[i])) tests_pass = false; } NTL_EXEC_RANGE_END if (tests_pass) { n = N; return; } // very unlikey to get here initial_counter = low_water_mark1 + 1; } } void GenGermainPrime(ZZ& n, long k, long err) { if (k <= 1) LogicError("GenGermainPrime: bad length"); if (k > (1L << 20)) ResourceError("GenGermainPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } if (k >= 192) { MultiThreadedGenGermainPrime(n, k, err); return; } long prime_bnd = ComputePrimeBound(k); if (NumBits(prime_bnd) >= k/2) prime_bnd = (1L << (k/2-1)); ZZ two; two = 2; ZZ n1; PrimeSeq s; ZZ iter; iter = 0; for (;;) { iter++; RandomLen(n, k); if (!IsOdd(n)) add(n, n, 1); s.reset(3); long p; long sieve_passed = 1; p = s.next(); while (p && p < prime_bnd) { long r = rem(n, p); if (r == 0) { sieve_passed = 0; break; } // test if 2*r + 1 = 0 (mod p) if (r == p-r-1) { sieve_passed = 0; break; } p = s.next(); } if (!sieve_passed) continue; if (MillerWitness(n, two)) continue; // n1 = 2*n+1 mul(n1, n, 2); add(n1, n1, 1); if (MillerWitness(n1, two)) continue; // now do t M-R iterations...just to make sure // First compute the appropriate number of M-R iterations, t // The following computes t such that // p(k,t)*8/k <= 2^{-err}/(5*iter^{1.25}) // which suffices to get an overall error probability of 2^{-err}. // Note that this method has the advantage of not requiring // any assumptions on the density of Germain primes. long err1 = max(1, err + 7 + (5*NumBits(iter) + 3)/4 - NumBits(k)); long t; t = 1; while (!ErrBoundTest(k, t, err1)) t++; ZZ W; long MR_passed = 1; long i; for (i = 1; i <= t; i++) { do { RandomBnd(W, n); } while (W == 0); // W == 0 is not a useful candidate witness! if (MillerWitness(n, W)) { MR_passed = 0; break; } } if (MR_passed) break; } } void OldGenGermainPrime(ZZ& n, long k, long err) { if (k <= 1) LogicError("GenGermainPrime: bad length"); if (k > (1L << 20)) ResourceError("GenGermainPrime: length too large"); if (err < 1) err = 1; if (err > 512) err = 512; if (k == 2) { if (RandomBnd(2)) n = 3; else n = 2; return; } long prime_bnd = ComputePrimeBound(k); if (NumBits(prime_bnd) >= k/2) prime_bnd = (1L << (k/2-1)); ZZ two; two = 2; ZZ n1; PrimeSeq s; ZZ iter; iter = 0; for (;;) { iter++; RandomLen(n, k); if (!IsOdd(n)) add(n, n, 1); s.reset(3); long p; long sieve_passed = 1; p = s.next(); while (p && p < prime_bnd) { long r = rem(n, p); if (r == 0) { sieve_passed = 0; break; } // test if 2*r + 1 = 0 (mod p) if (r == p-r-1) { sieve_passed = 0; break; } p = s.next(); } if (!sieve_passed) continue; if (MillerWitness(n, two)) continue; // n1 = 2*n+1 mul(n1, n, 2); add(n1, n1, 1); if (MillerWitness(n1, two)) continue; // now do t M-R iterations...just to make sure // First compute the appropriate number of M-R iterations, t // The following computes t such that // p(k,t)*8/k <= 2^{-err}/(5*iter^{1.25}) // which suffices to get an overall error probability of 2^{-err}. // Note that this method has the advantage of not requiring // any assumptions on the density of Germain primes. long err1 = max(1, err + 7 + (5*NumBits(iter) + 3)/4 - NumBits(k)); long t; t = 1; while (!ErrBoundTest(k, t, err1)) t++; ZZ W; long MR_passed = 1; long i; for (i = 1; i <= t; i++) { do { RandomBnd(W, n); } while (W == 0); // W == 0 is not a useful candidate witness! if (MillerWitness(n, W)) { MR_passed = 0; break; } } if (MR_passed) break; } } long GenGermainPrime_long(long k, long err) { if (k >= NTL_BITS_PER_LONG-1) ResourceError("GenGermainPrime_long: length too long"); ZZ n; GenGermainPrime(n, k, err); return to_long(n); } NTL_END_IMPL ntl-11.5.1/src/ZZVec.cpp0000644417616742025610000000223114064716022016447 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void ZZVec::SetSize(long n, long d) { if (n < 0 || d <= 0) LogicError("bad args to ZZVec::SetSize()"); if (v) LogicError("illegal ZZVec initialization"); if (n == 0) { len = n; bsize = d; return; } ZZVec tmp; tmp.len = 0; tmp.bsize = d; tmp.v = (ZZ*) NTL_SNS_MALLOC(n, sizeof(ZZ), 0); if (!tmp.v) MemoryError(); long i = 0; long m; long j; while (i < n) { m = ZZ_BlockConstructAlloc(tmp.v[i], d, n-i); for (j = 1; j < m; j++) ZZ_BlockConstructSet(tmp.v[i], tmp.v[i+j], j); i += m; tmp.len = i; } tmp.swap(*this); } void ZZVec::kill() { long n = len; long i = 0; while (i < n) { long m = ZZ_BlockDestroy(v[i]); i += m; } len = 0; bsize = 0; if (v) { free(v); v = 0; } } ZZVec& ZZVec::operator=(const ZZVec& a) { if (this == &a) return *this; ZZVec tmp(a); tmp.swap(*this); return *this; } ZZVec::ZZVec(const ZZVec& a) : v(0), len(0), bsize(0) { SetSize(a.len, a.bsize); long i; for (i = 0; i < a.len; i++) v[i] = (a.v)[i]; } NTL_END_IMPL ntl-11.5.1/src/ZZX.cpp0000644417616742025610000004550214064716022016151 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL const ZZX& ZZX::zero() { static const ZZX z; // GLOBAL (relies on C++11 thread-safe init) return z; } void conv(ZZ_pX& x, const ZZX& a) { conv(x.rep, a.rep); x.normalize(); } void conv(ZZX& x, const ZZ_pX& a) { conv(x.rep, a.rep); x.normalize(); } istream& operator>>(istream& s, ZZX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZX& a) { return s << a.rep; } void ZZX::normalize() { long n; const ZZ* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZX& a) { return a.rep.length() == 0; } long IsOne(const ZZX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const ZZX& a, const ZZX& b) { long i, n; const ZZ *ap, *bp; n = a.rep.length(); if (n != b.rep.length()) return 0; ap = a.rep.elts(); bp = b.rep.elts(); for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } long operator==(const ZZX& a, long b) { if (b == 0) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } long operator==(const ZZX& a, const ZZ& b) { if (IsZero(b)) return IsZero(a); if (deg(a) != 0) return 0; return a.rep[0] == b; } void GetCoeff(ZZ& x, const ZZX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(ZZX& x, long i, const ZZ& a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { ZZ aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ& coeff(const ZZX& a, long i) { if (i < 0 || i > deg(a)) return ZZ::zero(); else return a.rep[i]; } const ZZ& LeadCoeff(const ZZX& a) { if (IsZero(a)) return ZZ::zero(); else return a.rep[deg(a)]; } const ZZ& ConstTerm(const ZZX& a) { if (IsZero(a)) return ZZ::zero(); else return a.rep[0]; } void conv(ZZX& x, const ZZ& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(ZZX& x, long a) { if (a == 0) x.rep.SetLength(0); else { x.rep.SetLength(1); conv(x.rep[0], a); } } void conv(ZZX& x, const vec_ZZ& a) { x.rep = a; x.normalize(); } void add(ZZX& x, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ *ap, *bp; ZZ* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZX& x, const ZZX& a, const ZZ& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZX& x, const ZZX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZX& x, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ *ap, *bp; ZZ* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZX& x, const ZZX& a, const ZZ& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZX& x, const ZZX& a, long b) { if (b == 0) { x = a; return; } if (a.rep.length() == 0) { x.rep.SetLength(1); conv(x.rep[0], b); negate(x.rep[0], x.rep[0]); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(ZZX& x, long a, const ZZX& b) { negate(x, b); add(x, x, a); } void sub(ZZX& x, const ZZ& b, const ZZX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void negate(ZZX& x, const ZZX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ* ap = a.rep.elts(); ZZ* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } long MaxBits(const ZZX& f) { long i, m; m = 0; for (i = 0; i <= deg(f); i++) { m = max(m, NumBits(f.rep[i])); } return m; } void PlainMul(ZZX& x, const ZZX& a, const ZZX& b) { if (&a == &b) { PlainSqr(x, a); return; } long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const ZZ *ap, *bp; ZZ *xp; ZZX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; ZZ t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], bp[i-j]); add(accum, accum, t); } xp[i] = accum; } x.normalize(); } void PlainSqr(ZZX& x, const ZZX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long d = 2*da; const ZZ *ap; ZZ *xp; ZZX la; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; long m, m2; ZZ t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], ap[i-j]); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, ap[jmax + 1]); add(accum, accum, t); } xp[i] = accum; } x.normalize(); } static void PlainMul(ZZ *xp, const ZZ *ap, long sa, const ZZ *bp, long sb) { if (sa == 0 || sb == 0) return; long sx = sa+sb-1; long i, j, jmin, jmax; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i < sx; i++) { jmin = max(0, i-sb+1); jmax = min(sa-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], bp[i-j]); add(accum, accum, t); } xp[i] = accum; } } static void KarFold(ZZ *T, const ZZ *b, long sb, long hsa) { long m = sb - hsa; long i; for (i = 0; i < m; i++) add(T[i], b[i], b[hsa+i]); for (i = m; i < hsa; i++) T[i] = b[i]; } static void KarSub(ZZ *T, const ZZ *b, long sb) { long i; for (i = 0; i < sb; i++) sub(T[i], T[i], b[i]); } static void KarAdd(ZZ *T, const ZZ *b, long sb) { long i; for (i = 0; i < sb; i++) add(T[i], T[i], b[i]); } static void KarFix(ZZ *c, const ZZ *b, long sb, long hsa) { long i; for (i = 0; i < hsa; i++) c[i] = b[i]; for (i = hsa; i < sb; i++) add(c[i], c[i], b[i]); } static void PlainMul1(ZZ *xp, const ZZ *ap, long sa, const ZZ& b) { long i; for (i = 0; i < sa; i++) mul(xp[i], ap[i], b); } static void KarMul(ZZ *c, const ZZ *a, long sa, const ZZ *b, long sb, ZZ *stk, long sp) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const ZZ *t = a; a = b; b = t; } } if (sb == 1) { if (sa == 1) mul(*c, *a, *b); else PlainMul1(c, a, sa, *b); return; } if (sa == 2) { /* (sa => sb != 1) implies sb == 2 */ add(c[0], a[0], a[1]); add(c[2], b[0], b[1]); mul(c[1], c[0], c[2]); mul(c[0], a[0], b[0]); mul(c[2], a[1], b[1]); sub(c[1], c[1], c[0]); sub(c[1], c[1], c[2]); return; } if (sa == 3 && sb == 3) { add(c[0], a[0], a[2]); /* a_0 + a_2 */ add(c[2], a[1], a[2]); /* a_1 + a_2 */ add(c[1], b[0], b[2]); /* b_0 + b_2 */ add(c[4], b[1], b[2]); /* b_1 + b_2 */ mul(c[3], c[2], c[4]); /* (a_1 + a_2) x (b_1 + b_2) */ mul(c[2], c[0], c[1]); /* (a_0 + a_2) x (b_0 + b_2) */ add(c[0], a[0], a[1]); /* a_0 + a_1 */ add(c[4], b[0], b[1]); /* b_0 + b_1 */ mul(c[1], c[0], c[4]); /* (a_0 + a_1) x (b_0 + b_1) */ mul(c[0], a[1], b[1]); /* (a_1) x (b_1) */ sub(c[1], c[1], c[0]); sub(c[3], c[3], c[0]); add(c[2], c[2], c[0]); mul(c[0], a[0], b[0]); /* (a_0) x (b_0) */ sub(c[1], c[1], c[0]); sub(c[2], c[2], c[0]); mul(c[4], a[2], b[2]); /* (a_2) x (b_2) */ sub(c[3], c[3], c[4]); sub(c[2], c[2], c[4]); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; ZZ *T1, *T2, *T3; sp -= hsa2 - 1; if (sp < 0) TerminalError("internal error: KarMul overflow"); T1 = c; T2 = c + hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk, sp); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk, sp); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk, sp); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ ZZ *T; sp -= hsa + sb - 1; if (sp < 0) TerminalError("internal error: KarMul overflow"); T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk, sp); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk, sp); KarFix(c, T, hsa + sb - 1, hsa); } } void KarMul(ZZX& c, const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { KarSqr(c, a); return; } vec_ZZ mem; const ZZ *ap, *bp; ZZ *cp; long sa = a.rep.length(); long sb = b.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); if (&b == &c) { mem = b.rep; bp = mem.elts(); } else bp = b.rep.elts(); c.rep.SetLength(sa+sb-1); cp = c.rep.elts(); long maxa, maxb, xover; maxa = MaxBits(a); maxb = MaxBits(b); xover = 2; if (sa < xover || sb < xover) PlainMul(cp, ap, sa, bp, sb); else { /* karatsuba */ long n, hn, sp, depth; n = max(sa, sb); sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += (hn << 1) - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((maxa + maxb + NumBits(min(sa, sb)) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarMul(cp, ap, sa, bp, sb, stk.elts(), sp); } c.normalize(); } void PlainSqr(ZZ* xp, const ZZ* ap, long sa) { if (sa == 0) return; long da = sa-1; long d = 2*da; long i, j, jmin, jmax; long m, m2; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, ap[j], ap[i-j]); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, ap[jmax + 1]); add(accum, accum, t); } xp[i] = accum; } } static void KarSqr(ZZ *c, const ZZ *a, long sa, ZZ *stk) { if (sa == 1) { sqr(*c, *a); return; } if (sa == 2) { sqr(c[0], a[0]); sqr(c[2], a[1]); mul(c[1], a[0], a[1]); add(c[1], c[1], c[1]); return; } if (sa == 3) { sqr(c[0], a[0]); mul(c[1], a[0], a[1]); add(c[1], c[1], c[1]); sqr(c[3], a[1]); mul(c[2], a[0], a[2]); add(c[2], c[2], c[2]); add(c[2], c[2], c[3]); mul(c[3], a[1], a[2]); add(c[3], c[3], c[3]); sqr(c[4], a[2]); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; ZZ *T1, *T2; T1 = c; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr(T2, T1, hsa, stk); KarSqr(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void KarSqr(ZZX& c, const ZZX& a) { if (IsZero(a)) { clear(c); return; } vec_ZZ mem; const ZZ *ap; ZZ *cp; long sa = a.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); c.rep.SetLength(sa+sa-1); cp = c.rep.elts(); long maxa, xover; maxa = MaxBits(a); xover = 2; if (sa < xover) PlainSqr(cp, ap, sa); else { /* karatsuba */ long n, hn, sp, depth; n = sa; sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += hn+hn - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((2*maxa + NumBits(sa) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarSqr(cp, ap, sa, stk.elts()); } c.normalize(); } // specialized versions for ZZ_pX, with lower overhead // for memory allocations...used mainly for testing purposes void KarSqr(ZZ_pX& c, const ZZ_pX& a) { if (IsZero(a)) { clear(c); return; } long sa = a.rep.length(); long xover = 2; if (sa < xover) { PlainSqr(c, a); return; } ZZ *ap; ZZ *cp; ZZVec a_elts; a_elts.SetSize(sa, ZZ_p::ModulusSize()); ap = a_elts.elts(); for (long i = 0; i < sa; i++) ap[i] = rep(a.rep[i]); long sc = sa + sa - 1; ZZVec c_elts; c_elts.SetSize(sc, ZZ_p::ExtendedModulusSize()); cp = c_elts.elts(); long maxa, maxb; maxa = maxb = NumBits(ZZ_p::modulus()); long n, hn, sp, depth; n = sa; sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += (hn << 1) - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((maxa + maxb + NumBits(sa) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarSqr(cp, ap, sa, stk.elts()); c.rep.SetLength(sc); for (long i = 0; i < sc; i++) conv(c.rep[i], cp[i]); c.normalize(); } void KarMul(ZZ_pX& c, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { KarSqr(c, a); return; } long sa = a.rep.length(); long sb = b.rep.length(); long xover = 2; if (sa < xover || sb < xover) { PlainMul(c, a, b); return; } ZZ *ap, *bp; ZZ *cp; ZZVec a_elts; a_elts.SetSize(sa, ZZ_p::ModulusSize()); ap = a_elts.elts(); for (long i = 0; i < sa; i++) ap[i] = rep(a.rep[i]); ZZVec b_elts; b_elts.SetSize(sb, ZZ_p::ModulusSize()); bp = b_elts.elts(); for (long i = 0; i < sb; i++) bp[i] = rep(b.rep[i]); long sc = sa + sb - 1; ZZVec c_elts; c_elts.SetSize(sc, ZZ_p::ExtendedModulusSize()); cp = c_elts.elts(); long maxa, maxb; maxa = maxb = NumBits(ZZ_p::modulus()); long n, hn, sp, depth; n = max(sa, sb); sp = 0; depth = 0; do { hn = (n+1) >> 1; sp += (hn << 1) - 1; n = hn; depth++; } while (n >= xover); ZZVec stk; stk.SetSize(sp, ((maxa + maxb + NumBits(min(sa, sb)) + 2*depth + 10) + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); KarMul(cp, ap, sa, bp, sb, stk.elts(), sp); c.rep.SetLength(sc); for (long i = 0; i < sc; i++) conv(c.rep[i], cp[i]); c.normalize(); } NTL_END_IMPL ntl-11.5.1/src/ZZX1.cpp0000644417616742025610000021642714064716022016240 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL struct NewFastCRTHelperScratch { Vec tmp_vec; // length == nlevels+1 ZZ tmp1, tmp2, tmp3; }; struct NewFastCRTHelper { ZZ prod; ZZ prod_half; long nprimes; long nlevels; long veclen; long nblocks; // number of nodes in the last level long start_last_level; // index of first item in last level Vec nprimes_vec; // length == veclen Vec first_vec; // length == nblocks Vec prod_vec; // length == veclen Vec coeff_vec; // length == nprimes, coeff_vec[i] = (prod/p_i)^{-1} mod p_i Vec prime_vec; // length == nprimes Vec red_struct_vec; // length == nprimes Vec coeffpinv_vec; // length == nprimes Vec ppvec; // length == nblocks long GetNumPrimes() const { return nprimes; } NewFastCRTHelper(long bound); void fill_nprimes_vec(long index); void fill_prod_vec(long index); void reduce_aux(const ZZ& value, long *remainders, NewFastCRTHelperScratch& scratch, long index, long level) const; void reconstruct_aux(ZZ& value, const long* remainders, NewFastCRTHelperScratch& scratch, long index, long level) const; void reduce(const ZZ& value, long *remainders, NewFastCRTHelperScratch& scratch) const; void reconstruct(ZZ& value, const long *remainders, NewFastCRTHelperScratch& scratch) const; void init_scratch(NewFastCRTHelperScratch& scratch) const; }; void NewFastCRTHelper::init_scratch(NewFastCRTHelperScratch& scratch) const { scratch.tmp_vec.SetLength(nlevels+1); } void NewFastCRTHelper::fill_nprimes_vec(long index) { long left, right; left = 2*index + 1; right = 2*index + 2; if (left >= veclen) return; nprimes_vec[left] = nprimes_vec[index]/2; nprimes_vec[right] = nprimes_vec[index] - nprimes_vec[left]; fill_nprimes_vec(left); fill_nprimes_vec(right); } void NewFastCRTHelper::fill_prod_vec(long index) { long left, right; left = 2*index + 1; right = 2*index + 2; if (left >= veclen) return; fill_prod_vec(left); fill_prod_vec(right); mul(prod_vec[index], prod_vec[left], prod_vec[right]); } NewFastCRTHelper::NewFastCRTHelper(long bound) { long thresh = 96; bound += 2; // extra 2 bits ensures correct results // assumes bound >= 1, thresh >= 1 prod = 1; for (nprimes = 0; NumBits(prod) <= bound; nprimes++) { UseFFTPrime(nprimes); prod *= GetFFTPrime(nprimes); } RightShift(prod_half, prod, 1); long sz = nprimes; nlevels = 1; while (sz > thresh) { sz = sz/2; nlevels++; } veclen = (1L << nlevels) - 1; nblocks = 1L << (nlevels-1); start_last_level = (1L << (nlevels-1)) - 1; nprimes_vec.SetLength(veclen); nprimes_vec[0] = nprimes; fill_nprimes_vec(0); first_vec.SetLength(nblocks+1); first_vec[0] = 0; for (long k = 1; k <= nblocks; k++) first_vec[k] = first_vec[k-1] + nprimes_vec[start_last_level + k-1]; prod_vec.SetLength(veclen); // fill product leaves for (long k = 0; k < nblocks; k++) { prod_vec[start_last_level + k] = 1; for (long i = first_vec[k]; i < first_vec[k+1]; i++) { prod_vec[start_last_level + k] *= GetFFTPrime(i); } } // fill rest of product trees fill_prod_vec(0); ZZ t1; coeff_vec.SetLength(nprimes); prime_vec.SetLength(nprimes); red_struct_vec.SetLength(nprimes); coeffpinv_vec.SetLength(nprimes); for (long i = 0; i < nprimes; i++) { long p = GetFFTPrime(i); div(t1, prod, p); long tt = rem(t1, p); tt = InvMod(tt, p); coeff_vec[i] = tt; prime_vec[i] = p; red_struct_vec[i] = &GetFFT_ZZ_red_struct(i); coeffpinv_vec[i] = PrepMulModPrecon(tt, p); } ppvec.SetLength(nblocks); for (long k = 0; k < nblocks; k++) { const ZZ& block_prod = prod_vec[start_last_level + k]; ppvec[k].SetSize(first_vec[k+1]-first_vec[k], block_prod.size()); for (long i = first_vec[k]; i < first_vec[k+1]; i++) { div(t1, block_prod, prime_vec[i]); ppvec[k][i-first_vec[k]] = t1; } } } void NewFastCRTHelper::reduce_aux(const ZZ& value, long *remainders, NewFastCRTHelperScratch& scratch, long index, long level) const { long left, right; left = 2*index + 1; right = 2*index + 2; ZZ& result = scratch.tmp_vec[level]; if (NumBits(value) <= NumBits(prod_vec[index])) result = value; else { rem(scratch.tmp1, value, prod_vec[index]); sub(scratch.tmp2, scratch.tmp1, prod_vec[index]); if (NumBits(scratch.tmp2) < NumBits(scratch.tmp1)) result = scratch.tmp2; else result = scratch.tmp1; } if (left < veclen) { reduce_aux(result, remainders, scratch, left, level+1); reduce_aux(result, remainders, scratch, right, level+1); } else { long k = index - start_last_level; long i_begin = first_vec[k]; long i_end = first_vec[k+1]; for (long i = i_begin; i < i_end; i++) { remainders[i] = red_struct_vec[i]->rem(result); } } } void NewFastCRTHelper::reduce(const ZZ& value, long *remainders, NewFastCRTHelperScratch& scratch) const { reduce_aux(value, remainders, scratch, 0, 0); } void NewFastCRTHelper::reconstruct_aux(ZZ& value, const long* remainders, NewFastCRTHelperScratch& scratch, long index, long level) const { long left, right; left = 2*index + 1; right = 2*index + 2; if (left >= veclen) { long k = index - start_last_level; long i_begin = first_vec[k]; long i_end = first_vec[k+1]; const ZZ* ppv = ppvec[k].elts(); ZZ& acc = scratch.tmp1; QuickAccumBegin(acc, prod_vec[index].size()); for (long i = i_begin; i < i_end; i++) { long p = prime_vec[i]; long tt = coeff_vec[i]; mulmod_precon_t ttpinv = coeffpinv_vec[i]; long s = MulModPrecon(remainders[i], tt, p, ttpinv); QuickAccumMulAdd(acc, ppv[i-i_begin], s); } QuickAccumEnd(acc); value = acc; return; } reconstruct_aux(scratch.tmp_vec[level], remainders, scratch, left, level+1); reconstruct_aux(scratch.tmp1, remainders, scratch, right, level+1); mul(scratch.tmp2, scratch.tmp_vec[level], prod_vec[right]); mul(scratch.tmp3, scratch.tmp1, prod_vec[left]); add(value, scratch.tmp2, scratch.tmp3); } void NewFastCRTHelper::reconstruct(ZZ& value, const long *remainders, NewFastCRTHelperScratch& scratch) const { reconstruct_aux(scratch.tmp1, remainders, scratch, 0, 0); rem(scratch.tmp2, scratch.tmp1, prod); if (scratch.tmp2 > prod_half) sub(scratch.tmp2, scratch.tmp2, prod); value = scratch.tmp2; } #define CRT_BLK (8) void HomMul(ZZX& x, const ZZX& a, const ZZX& b) { if (&a == &b) { HomSqr(x, a); return; } long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long dc = da + db; zz_pBak bak; bak.save(); long bound = NumBits(min(da, db)+1) + MaxBits(a) + MaxBits(b); NewFastCRTHelper H(bound); long nprimes = H.GetNumPrimes(); if (NTL_OVERFLOW(nprimes, CRT_BLK, 0)) ResourceError("overflow"); // this is pretty academic Vec< zz_pX > A, B, C; A.SetLength(nprimes); for (long i = 0; i < nprimes; i++) A[i].SetLength(da+1); NTL_EXEC_RANGE(da+1, first, last) { Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); long *remainders = remainders_store.elts(); NewFastCRTHelperScratch scratch; H.init_scratch(scratch); long jj = first; for (; jj <= last-CRT_BLK; jj += CRT_BLK) { for (long j = 0; j < CRT_BLK; j++) H.reduce(a[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Ai = A[i].rep.elts(); for (long j = 0; j < CRT_BLK; j++) Ai[jj+j].LoopHole() = remainders[j*nprimes+i]; } } if (jj < last) { for (long j = 0; j < last-jj; j++) H.reduce(a[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Ai = A[i].rep.elts(); for (long j = 0; j < last-jj; j++) Ai[jj+j].LoopHole() = remainders[j*nprimes+i]; } } } NTL_EXEC_RANGE_END B.SetLength(nprimes); for (long i = 0; i < nprimes; i++) B[i].SetLength(db+1); NTL_EXEC_RANGE(db+1, first, last) { Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); long *remainders = remainders_store.elts(); NewFastCRTHelperScratch scratch; H.init_scratch(scratch); long jj = first; for (; jj <= last-CRT_BLK; jj += CRT_BLK) { for (long j = 0; j < CRT_BLK; j++) H.reduce(b[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Bi = B[i].rep.elts(); for (long j = 0; j < CRT_BLK; j++) Bi[jj+j].LoopHole() = remainders[j*nprimes+i]; } } if (jj < last) { for (long j = 0; j < last-jj; j++) H.reduce(b[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Bi = B[i].rep.elts(); for (long j = 0; j < last-jj; j++) Bi[jj+j].LoopHole() = remainders[j*nprimes+i]; } } } NTL_EXEC_RANGE_END C.SetLength(nprimes); for (long i = 0; i < nprimes; i++) C[i].SetMaxLength(dc+1); NTL_EXEC_RANGE(nprimes, first, last) for (long i = first; i < last; i++) { zz_p::FFTInit(i); A[i].normalize(); B[i].normalize(); mul(C[i], A[i], B[i]); long dci = deg(C[i]); C[i].SetLength(dc+1); if (dci < dc) { zz_p *Ci = C[i].rep.elts(); for (long j = dci+1; j <= dc; j++) Ci[j] = 0; } } NTL_EXEC_RANGE_END ZZVec xx; xx.SetSize(dc+1, (bound+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); // NOTE: we pre-allocate all the storage we // need to collect the result. Based on my experience, // too many calls to malloc in a multi-threaded setting // can lead to significant performance degredation NTL_EXEC_RANGE(dc+1, first, last) { Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); long *remainders = remainders_store.elts(); NewFastCRTHelperScratch scratch; H.init_scratch(scratch); long jj = first; for (; jj <= last-CRT_BLK; jj += CRT_BLK) { for (long i = 0; i < nprimes; i++) { zz_p *Ci = C[i].rep.elts(); for (long j = 0; j < CRT_BLK; j++) remainders[j*nprimes+i] = rep(Ci[jj+j]); } for (long j = 0; j < CRT_BLK; j++) H.reconstruct(xx[jj+j], remainders + j*nprimes, scratch); } if (jj < last) { for (long i = 0; i < nprimes; i++) { zz_p *Ci = C[i].rep.elts(); for (long j = 0; j < last-jj; j++) remainders[j*nprimes+i] = rep(Ci[jj+j]); } for (long j = 0; j < last-jj; j++) H.reconstruct(xx[jj+j], remainders + j*nprimes, scratch); } } NTL_EXEC_RANGE_END x.SetLength(dc+1); for (long j = 0; j <=dc; j++) x[j] = xx[j]; x.normalize(); } void HomSqr(ZZX& x, const ZZX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long dc = da + da; zz_pBak bak; bak.save(); long bound = NumBits(da+1) + 2*MaxBits(a); NewFastCRTHelper H(bound); long nprimes = H.GetNumPrimes(); if (NTL_OVERFLOW(nprimes, CRT_BLK, 0)) ResourceError("overflow"); // this is pretty academic Vec< zz_pX > A, C; A.SetLength(nprimes); for (long i = 0; i < nprimes; i++) A[i].SetLength(da+1); NTL_EXEC_RANGE(da+1, first, last) { Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); long *remainders = remainders_store.elts(); NewFastCRTHelperScratch scratch; H.init_scratch(scratch); long jj = first; for (; jj <= last-CRT_BLK; jj += CRT_BLK) { for (long j = 0; j < CRT_BLK; j++) H.reduce(a[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Ai = A[i].rep.elts(); for (long j = 0; j < CRT_BLK; j++) Ai[jj+j].LoopHole() = remainders[j*nprimes+i]; } } if (jj < last) { for (long j = 0; j < last-jj; j++) H.reduce(a[jj+j], remainders + j*nprimes, scratch); for (long i = 0; i < nprimes; i++) { zz_p *Ai = A[i].rep.elts(); for (long j = 0; j < last-jj; j++) Ai[jj+j].LoopHole() = remainders[j*nprimes+i]; } } } NTL_EXEC_RANGE_END C.SetLength(nprimes); for (long i = 0; i < nprimes; i++) C[i].SetMaxLength(dc+1); NTL_EXEC_RANGE(nprimes, first, last) for (long i = first; i < last; i++) { zz_p::FFTInit(i); A[i].normalize(); sqr(C[i], A[i]); long dci = deg(C[i]); C[i].SetLength(dc+1); if (dci < dc) { zz_p *Ci = C[i].rep.elts(); for (long j = dci+1; j <= dc; j++) Ci[j] = 0; } } NTL_EXEC_RANGE_END ZZVec xx; xx.SetSize(dc+1, (bound+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); // NOTE: we pre-allocate all the storage we // need to collect the result. Based on my experience, // too many calls to malloc in a multi-threaded setting // can lead to significant performance degredation NTL_EXEC_RANGE(dc+1, first, last) { Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); long *remainders = remainders_store.elts(); NewFastCRTHelperScratch scratch; H.init_scratch(scratch); long jj = first; for (; jj <= last-CRT_BLK; jj += CRT_BLK) { for (long i = 0; i < nprimes; i++) { zz_p *Ci = C[i].rep.elts(); for (long j = 0; j < CRT_BLK; j++) remainders[j*nprimes+i] = rep(Ci[jj+j]); } for (long j = 0; j < CRT_BLK; j++) H.reconstruct(xx[jj+j], remainders + j*nprimes, scratch); } if (jj < last) { for (long i = 0; i < nprimes; i++) { zz_p *Ci = C[i].rep.elts(); for (long j = 0; j < last-jj; j++) remainders[j*nprimes+i] = rep(Ci[jj+j]); } for (long j = 0; j < last-jj; j++) H.reconstruct(xx[jj+j], remainders + j*nprimes, scratch); } } NTL_EXEC_RANGE_END x.SetLength(dc+1); for (long j = 0; j <=dc; j++) x[j] = xx[j]; x.normalize(); } static long MaxSize(const ZZX& a) { long res = 0; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { long t = a.rep[i].size(); if (t > res) res = t; } return res; } void conv(zz_pX& x, const ZZX& a) { conv(x.rep, a.rep); x.normalize(); } void conv(ZZX& x, const zz_pX& a) { conv(x.rep, a.rep); x.normalize(); } long CRT(ZZX& gg, ZZ& a, const zz_pX& G) { long n = gg.rep.length(); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; long m = G.rep.length(); long max_mn = max(m, n); gg.rep.SetLength(max_mn); ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg.rep[i], a)) { modified = 1; rem(g, gg.rep[i], a); if (g > a1) sub(g, g, a); } else g = gg.rep[i]; h = rem(g, p); if (i < m) h = SubMod(rep(G.rep[i]), h, p); else h = NegateMod(h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg.rep[i] = g; } for (; i < m; i++) { h = rep(G.rep[i]); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; modified = 1; mul(g, a, h); gg.rep[i] = g; } gg.normalize(); a = new_a; return modified; } long CRT(ZZX& gg, ZZ& a, const ZZ_pX& G) { long n = gg.rep.length(); const ZZ& p = ZZ_p::modulus(); ZZ new_a; mul(new_a, a, p); ZZ a_inv; rem(a_inv, a, p); InvMod(a_inv, a_inv, p); ZZ p1; RightShift(p1, p, 1); ZZ a1; RightShift(a1, a, 1); long p_odd = IsOdd(p); long modified = 0; ZZ h; ZZ ah; long m = G.rep.length(); long max_mn = max(m, n); gg.rep.SetLength(max_mn); ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg.rep[i], a)) { modified = 1; rem(g, gg.rep[i], a); if (g > a1) sub(g, g, a); } else g = gg.rep[i]; rem(h, g, p); if (i < m) SubMod(h, rep(G.rep[i]), h, p); else NegateMod(h, h, p); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); if (h != 0) { modified = 1; mul(ah, a, h); if (!p_odd && g > 0 && (h == p1)) sub(g, g, ah); else add(g, g, ah); } gg.rep[i] = g; } for (; i < m; i++) { h = rep(G.rep[i]); MulMod(h, h, a_inv, p); if (h > p1) sub(h, h, p); modified = 1; mul(g, a, h); gg.rep[i] = g; } gg.normalize(); a = new_a; return modified; } #define SS_PAR_THRESH (2000.0) //#define SS_PAR_THRESH (10.0) // For testing static inline bool SS_BelowThresh(long n, long k) { return double(n)*double(k) < SS_PAR_THRESH; } static void SS_AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& p, long n) // x = a + b mod p, where p = 2^n+1, a, b in [0, p). // x may not alias p. { #ifndef NTL_PROVIDES_SS_LIP_IMPL add(x, a, b); if (x >= p) { x--; SwitchBit(x, n); // x -= p } #else SS_AddMod_lip_impl(x, a, b, p, n); #endif } static void SS_SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& p, long n) // x = a - b mod p, where p = 2^n+1, a, b in [0, p). // x may not alias b or p. { #ifndef NTL_PROVIDES_SS_LIP_IMPL if (a < b) { add(x, a, p); SubPos(x, x, b); } else { SubPos(x, a, b); } #else SS_SubMod_lip_impl(x, a, b, p, n); #endif } /* Compute a = b * 2^e mod p, where p = 2^n+1. 0<=e= 0. // Returns an integer m such that 1 <= m <= n = 2^k and // m divsisible my 2^SS_FFT_RDUP. // Also, if xn <= n, then m >= xn. { long n = 1L << k; if (xn <= 0) xn = 1; xn = ((xn+((1L << SS_FFT_RDUP)-1)) >> SS_FFT_RDUP) << SS_FFT_RDUP; if (xn > n - (n >> 4)) xn = n; return xn; } // p = 2^n+1, where n = r*2^{l-1}, so 2^r is primitive 2^l-th root // of unity mod p. // j in [0, 2^{level-1}) // a = b*2^{j*r*2^{l-level}} static void Rotate(ZZ& a, const ZZ& b, long j, long level, long r, long l, const ZZ& p, long n, ZZ* tmp) { if (l-level >= 0) LeftRotate(a, b, (j*r) << (l-level), p, n, tmp[0]); else if (((j*r) & 1) == 0) LeftRotate(a, b, (j*r) >> 1, p, n, tmp[0]); else { // use sqrt(2) = 2^{3n/4} - 2^{n/4} long k = (j*r) >> 1; // j*r = 2*k + 1 // now compute a = b*2^{k+1/2} mod p // a = b*{2^k} mod p LeftRotate(a, b, k, p, n, tmp[0]); // tmp[1] = a*2^{n/4} mod p LeftRotate(tmp[1], a, n >> 2, p, n, tmp[0]); // a = a*2^{3n/4} mod p LeftRotate(a, a, 3*(n >> 2), p, n, tmp[0]); // a -= tmp[1] mod p SS_SubMod(a, a, tmp[1], p, n); } } static void SS_butterfly(ZZ& x, ZZ& y, const ZZ& p, long n, ZZ* tmp) // (x, y) := (x+y, x-y) { /* tmp[0] = x - y mod p */ SS_SubMod(tmp[0], x, y, p, n); /* x += y mod p */ SS_AddMod(x, x, y, p, n); y = tmp[0]; } static void SS_fwd_butterfly(ZZ& x, ZZ& y, long j, long level, long r, long l, const ZZ& p, long n, ZZ* tmp) // ( x, y ) *= ( 1 2^{j*r*2^{l-level}} ) // ( 1 -2^{j*r*2^{l-level}} ) { /* tmp[0] = x - y mod p */ SS_SubMod(tmp[0], x, y, p, n); /* x += y mod p */ SS_AddMod(x, x, y, p, n); /* y = tmp[0] * 2^{j*r*2^{l-level}} mod p */ Rotate(y, tmp[0], j, level, r, l, p, n, tmp+1); } static void SS_inv_butterfly(ZZ& x, ZZ& y, long j, long level, long r, long l, const ZZ& p, long n, ZZ* tmp) // ( x, y ) *= ( 1 1 ) // ( 2^{-j*r*2^{l-level}} -2^{-j*r*2^{l-level}} ) // *** should not be called with j == 0 // call SS_butterfly instead { /* tmp[0] = y * 2^{(2^{level-1}-j)*r*2^{l-level}} mod p */ Rotate(tmp[0], y, (1L<<(level-1))-j, level, r, l, p, n, tmp+1); /* y = x + tmp[0] mod p */ SS_AddMod(y, x, tmp[0], p, n); // NEGATED /* x = x - tmp[0] mod p */ SS_SubMod(x, x, tmp[0], p, n); // NEGATED } // Much of the following logic is taken from the code in FFT.cpp // for single-precision modular FFT's, which itself is adapted // from code originally written by David Harvey. // See copyright notice in FFT.cpp. // size == 2^level static void fft_layer(ZZ* xp, long blocks, long size, long level, long r, long l, const ZZ& p, long n, ZZ* tmp) { size /= 2; do { ZZ *xp0 = xp; ZZ *xp1 = xp + size; for (long j = 0; j < size; j++) SS_fwd_butterfly(xp0[j], xp1[j], j, level, r, l, p, n, tmp); xp += 2*size; } while (--blocks != 0); } static void fft_base(ZZ* xp, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp) { long N = 1L << lgN; for (long j = lgN, size = N, blocks = 1; j >= 1; j--, blocks <<= 1, size >>= 1) fft_layer(xp, blocks, size, j, r, l, p, n, tmp); } static void fft_rec(ZZ* xp, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp) { if (lgN <= SS_FFT_THRESH) { fft_base(xp, lgN, r, l, p, n, tmp); return; } long N = 1L << lgN; long half = N >> 1; ZZ *xp0 = xp; ZZ *xp1 = xp + half; for (long j = 0; j < half; j++) SS_fwd_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); fft_rec(xp0, lgN-1, r, l, p, n, tmp); fft_rec(xp1, lgN-1, r, l, p, n, tmp); } static void fft_short(ZZ* xp, long yn, long xn, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp, RecursiveThreadPool *pool) { Vec alt_tmp; if (!tmp) { alt_tmp.SetLength(SS_NTEMPS); tmp = &alt_tmp[0]; } long N = 1L << lgN; if (yn == N) { if (xn == N && lgN <= SS_FFT_THRESH) { // no truncation fft_base(xp, lgN, r, l, p, n, tmp); return; } } // divide-and-conquer algorithm long half = N >> 1; if (yn <= half) { if (xn <= half) { fft_short(xp, yn, xn, lgN-1, r, l, p, n, tmp, pool); } else { xn -= half; // (X, Y) -> X + Y for (long j = 0; j < xn; j++) SS_AddMod(xp[j], xp[j], xp[j + half], p, n); fft_short(xp, yn, half, lgN-1, r, l, p, n, tmp, pool); } } else { yn -= half; ZZ *xp0 = xp; ZZ *xp1 = xp + half; if (xn <= half) { // X -> (X, w*X) for (long j = 0; j < xn; j++) Rotate(xp1[j], xp0[j], j, lgN, r, l, p, n, tmp); bool seq = SS_BelowThresh(half+yn, p.size()); NTL_EXEC_DIVIDE(seq, pool, helper, double(half)/double(half+yn), fft_short(xp0, half, xn, lgN-1, r, l, p, n, tmp, helper.subpool(0)), fft_short(xp1, yn, xn, lgN-1, r, l, p, n, (helper.concurrent() ? 0 : tmp), helper.subpool(1))) } else { xn -= half; // (X, Y) -> (X + Y, w*(X - Y)) for (long j = 0; j < xn; j++) SS_fwd_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); // X -> (X, w*X) for (long j = xn; j < half; j++) Rotate(xp1[j], xp0[j], j, lgN, r, l, p, n, tmp); bool seq = SS_BelowThresh(half+yn, p.size()); NTL_EXEC_DIVIDE(seq, pool, helper, double(half)/double(half+yn), fft_short(xp0, half, half, lgN-1, r, l, p, n, tmp, helper.subpool(0)), fft_short(xp1, yn, half, lgN-1, r, l, p, n, (helper.concurrent() ? 0 : tmp), helper.subpool(1))) } } } static void fft(ZZVec& a, long r, long l, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; fft_rec(&a[0], l, r, l, p, n, &tmp[0]); } static void fft1(ZZVec& a, long r, long l, long l1, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; fft_rec(&a[0], l, r, l1, p, n, &tmp[0]); } static void fft_trunc(ZZVec& a, long yn, long xn, long r, long l, long l1, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; fft_short(&a[0], yn, xn, l, r, l1, p, n, &tmp[0], NTL_INIT_DIVIDE); } static void fft_trunc_pair(ZZVec& a_0, ZZVec& a_1, long yn, long xn_0, long xn_1, long r, long l, long l1, const ZZ& p, long n, RecursiveThreadPool* pool) { ZZ tmp_0[SS_NTEMPS]; ZZ tmp_1[SS_NTEMPS]; bool seq = SS_BelowThresh(yn, p.size()); NTL_EXEC_DIVIDE(seq, pool, helper, 0.5, fft_short(&a_0[0], yn, xn_0, l, r, l1, p, n, &tmp_0[0], helper.subpool(0)), fft_short(&a_1[0], yn, xn_1, l, r, l1, p, n, &tmp_1[0], helper.subpool(1))) } static void ifft_layer(ZZ* xp, long blocks, long size, long level, long r, long l, const ZZ& p, long n, ZZ* tmp) { size /= 2; do { ZZ *xp0 = xp; ZZ *xp1 = xp + size; SS_butterfly(xp0[0], xp1[0], p, n, tmp); for (long j = 1; j < size; j++) SS_inv_butterfly(xp0[j], xp1[j], j, level, r, l, p, n, tmp); xp += 2*size; } while (--blocks != 0); } static void ifft_base(ZZ* xp, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp) { long N = 1L << lgN; for (long j = 1, size = 2, blocks = N/2; j <= lgN; j++, blocks >>= 1, size <<= 1) ifft_layer(xp, blocks, size, j, r, l, p, n, tmp); } static void ifft_rec(ZZ* xp, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp) { if (lgN <= SS_FFT_THRESH) { ifft_base(xp, lgN, r, l, p, n, tmp); return; } long N = 1L << lgN; long half = N >> 1; ZZ *xp0 = xp; ZZ *xp1 = xp + half; ifft_rec(xp0, lgN-1, r, l, p, n, tmp); ifft_rec(xp1, lgN-1, r, l, p, n, tmp); SS_butterfly(xp0[0], xp1[0], p, n, tmp); for (long j = 1; j < half; j++) SS_inv_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); } static void ifft_short2(ZZ* xp, long yn, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp, RecursiveThreadPool* pool); static void ifft_short0(ZZ* xp, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp, RecursiveThreadPool* pool) { Vec alt_tmp; if (!tmp) { alt_tmp.SetLength(SS_NTEMPS); tmp = &alt_tmp[0]; } long N = 1L << lgN; if (lgN <= SS_FFT_THRESH) { // no truncation ifft_base(xp, lgN, r, l, p, n, tmp); return; } // divide-and-conquer algorithm long half = N >> 1; ZZ *xp0 = xp; ZZ *xp1 = xp + half; bool seq = SS_BelowThresh(N, p.size()); NTL_EXEC_DIVIDE(seq, pool, helper, 0.5, ifft_short0(xp0, lgN-1, r, l, p, n, tmp, helper.subpool(0)), ifft_short0(xp1, lgN-1, r, l, p, n, (helper.concurrent() ? 0 : tmp), helper.subpool(1))) // (X, Y) -> (X + Y/w, X - Y/w) SS_butterfly(xp0[0], xp1[0], p, n, tmp); for (long j = 1; j < half; j++) SS_inv_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); } static void ifft_short1(ZZ* xp, long yn, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp, RecursiveThreadPool* pool) { long N = 1L << lgN; if (yn == N) { // no truncation ifft_short0(xp, lgN, r, l, p, n, tmp, pool); return; } // divide-and-conquer algorithm long half = N >> 1; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j++) SS_AddMod(xp[j], xp[j], xp[j], p, n); ifft_short1(xp, yn, lgN-1, r, l, p, n, tmp, pool); } else { ZZ *xp0 = xp; ZZ *xp1 = xp + half; ifft_short0(xp0, lgN-1, r, l, p, n, tmp, pool); yn -= half; // X -> (2X, w*X) for (long j = yn; j < half; j++) { tmp[0] = xp0[j]; SS_AddMod(xp0[j], xp0[j], xp0[j], p, n); Rotate(xp1[j], tmp[0], j, lgN, r, l, p, n, tmp+1); } ifft_short2(xp1, yn, lgN-1, r, l, p, n, tmp, pool); // (X, Y) -> (X + Y/w, X - Y/w) SS_butterfly(xp0[0], xp1[0], p, n, tmp); for (long j = 1; j < yn; j++) SS_inv_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); } } static void ifft_short2(ZZ* xp, long yn, long lgN, long r, long l, const ZZ& p, long n, ZZ* tmp, RecursiveThreadPool* pool) { long N = 1L << lgN; if (yn == N) { // no truncation ifft_short0(xp, lgN, r, l, p, n, tmp, pool); return; } // divide-and-conquer algorithm long half = N >> 1; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j++) SS_AddMod(xp[j], xp[j], xp[j], p, n); // (X, Y) -> X + Y for (long j = yn; j < half; j++) SS_AddMod(xp[j], xp[j], xp[j + half], p, n); ifft_short2(xp, yn, lgN-1, r, l, p, n, tmp, pool); // (X, Y) -> X - Y for (long j = 0; j < yn; j++) SS_SubMod(xp[j], xp[j], xp[j + half], p, n); } else { ZZ *xp0 = xp; ZZ *xp1 = xp + half; ifft_short0(xp0, lgN-1, r, l, p, n, tmp, pool); yn -= half; // (X, Y) -> (2X - Y, w*(X - Y)) for (long j = yn; j < half; j++) { SS_SubMod(tmp[0], xp0[j], xp1[j], p, n); SS_AddMod(xp0[j], xp0[j], tmp[0], p, n); Rotate(xp1[j], tmp[0], j, lgN, r, l, p, n, tmp+1); } ifft_short2(xp1, yn, lgN-1, r, l, p, n, tmp, pool); // (X, Y) -> (X + Y/w, X - Y/w) SS_butterfly(xp0[0], xp1[0], p, n, tmp); for (long j = 1; j < yn; j++) SS_inv_butterfly(xp0[j], xp1[j], j, lgN, r, l, p, n, tmp); } } static void ifft(ZZVec& a, long r, long l, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; ifft_rec(&a[0], l, r, l, p, n, &tmp[0]); } static void ifft1(ZZVec& a, long r, long l, long l1, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; ifft_rec(&a[0], l, r, l1, p, n, &tmp[0]); } static void ifft_trunc(ZZVec& a, long yn, long r, long l, long l1, const ZZ& p, long n) { ZZ tmp[SS_NTEMPS]; ifft_short1(&a[0], yn, l, r, l1, p, n, &tmp[0], NTL_INIT_DIVIDE); } /* Multiplication a la Schoenhage & Strassen, modulo a "Fermat" number p = 2^{mr}+1, where m is a power of two and r is odd. Then w = 2^r is a primitive 2mth root of unity, i.e., polynomials whose product has degree less than 2m can be multiplied, provided that the coefficients of the product polynomial are at most 2^{mr-1} in absolute value. The algorithm is not called recursively; coefficient arithmetic is done directly.*/ // The original version of SSMUl was written by Juergen Gerhard. // However, it has been almost completely re-written so as // to provide the following improvements: // * uses truncated FFT and Inverse FFT algorithms, // for better performance between powers of 2 // * better cache locality because of divide and conquer structure // * better performance because of sqrt(2) trick void SSMul(ZZX& c, const ZZX& a, const ZZX& b) { if (&a == &b) { SSSqr(c, a); return; } long na = deg(a); long nb = deg(b); if (na <= 0 || nb <= 0) { PlainMul(c, a, b); return; } long n = na + nb; /* degree of the product */ /* Choose m and r suitably */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long N = 1L << (l + 1); /* N = 2^{l+1} */ /* Bitlength of the product: if the coefficients of a are absolutely less than 2^ka and the coefficients of b are absolutely less than 2^kb, then the coefficients of ab are absolutely less than (min(na,nb)+1)2^{ka+kb} <= 2^bound. */ long bound = 2 + NumBits(min(na, nb)) + MaxBits(a) + MaxBits(b); /* Let r be minimal so that mr > bound */ long r = (bound >> l) + 1; long mr = r << l; // sqrt(2) trick long l1 = l; if (l1 >= 3) { long alt_l1 = l-1; long alt_r = (bound >> alt_l1) + 1; long alt_mr = alt_r << alt_l1; if (alt_mr < mr - mr/8) { l1 = alt_l1; r = alt_r; mr = alt_mr; } } /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); /* Make coefficients of a and b positive */ ZZVec aa, bb; aa.SetSize(N, p.size()); bb.SetSize(N, p.size()); for (long i = 0; i <= deg(a); i++) { if (sign(a.rep[i]) >= 0) { aa[i] = a.rep[i]; } else { add(aa[i], a.rep[i], p); } } for (long i = 0; i <= deg(b); i++) { if (sign(b.rep[i]) >= 0) { bb[i] = b.rep[i]; } else { add(bb[i], b.rep[i], p); } } long yn = SS_FFTRoundUp(n+1, l+1); /* N-point FFT's mod p */ fft_trunc_pair(aa, bb, yn, SS_FFTRoundUp(na+1, l+1), SS_FFTRoundUp(nb+1, l+1), r, l+1, l1+1, p, mr, NTL_INIT_DIVIDE); //fft_trunc(aa, yn, SS_FFTRoundUp(na+1, l+1), r, l+1, l1+1, p, mr); //fft_trunc(bb, yn, SS_FFTRoundUp(nb+1, l+1), r, l+1, l1+1, p, mr); /* Pointwise multiplication aa := aa * bb mod p */ bool seq = SS_BelowThresh(yn, p.size()); NTL_GEXEC_RANGE(seq, yn, first, last) ZZ tmp, ai; for (long i = first; i < last; i++) { mul(ai, aa[i], bb[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } NTL_GEXEC_RANGE_END ifft_trunc(aa, yn, r, l+1, l1+1, p, mr); /* Retrieve c, dividing by N, and subtracting p where necessary */ c.rep.SetLength(n + 1); ZZ ai, tmp, scratch; for (long i = 0; i <= n; i++) { ai = aa[i]; ZZ& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / N mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr, scratch); sub(tmp, p, ai); if (NumBits(tmp) >= mr) { /* ci >= (p-1)/2 */ negate(ci, ai); /* ci = -ai = ci - p */ } else ci = tmp; } else clear(ci); } } void SSMul(ZZ_pX& c, const ZZ_pX& a, const ZZ_pX& b) { if (&a == &b) { SSSqr(c, a); return; } long na = deg(a); long nb = deg(b); if (na <= 0 || nb <= 0) { PlainMul(c, a, b); return; } long n = na + nb; /* degree of the product */ /* Choose m and r suitably */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long N = 1L << (l + 1); /* N = 2^{l+1} */ /* Bitlength of the product: if the coefficients of a are absolutely less than 2^ka and the coefficients of b are absolutely less than 2^kb, then the coefficients of ab are absolutely less than (min(na,nb)+1)2^{ka+kb} <= 2^bound. */ long bound = 2 + NumBits(min(na, nb)) + 2*NumBits(ZZ_p::modulus()); /* Let r be minimal so that mr > bound */ long r = (bound >> l) + 1; long mr = r << l; // sqrt(2) trick long l1 = l; if (l1 >= 3) { long alt_l1 = l-1; long alt_r = (bound >> alt_l1) + 1; long alt_mr = alt_r << alt_l1; if (alt_mr < mr - mr/8) { l1 = alt_l1; r = alt_r; mr = alt_mr; } } /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); ZZVec aa, bb; aa.SetSize(N, p.size()); bb.SetSize(N, p.size()); for (long i = 0; i <= deg(a); i++) { aa[i] = rep(a.rep[i]); } for (long i = 0; i <= deg(b); i++) { bb[i] = rep(b.rep[i]); } long yn = SS_FFTRoundUp(n+1, l+1); /* N-point FFT's mod p */ fft_trunc_pair(aa, bb, yn, SS_FFTRoundUp(na+1, l+1), SS_FFTRoundUp(nb+1, l+1), r, l+1, l1+1, p, mr, NTL_INIT_DIVIDE); //fft_trunc(aa, yn, SS_FFTRoundUp(na+1, l+1), r, l+1, l1+1, p, mr); //fft_trunc(bb, yn, SS_FFTRoundUp(nb+1, l+1), r, l+1, l1+1, p, mr); /* Pointwise multiplication aa := aa * bb mod p */ bool seq = SS_BelowThresh(yn, p.size()); NTL_GEXEC_RANGE(seq, yn, first, last) ZZ tmp, ai; for (long i = first; i < last; i++) { mul(ai, aa[i], bb[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } NTL_GEXEC_RANGE_END ifft_trunc(aa, yn, r, l+1, l1+1, p, mr); /* Retrieve c, dividing by N, and subtracting p where necessary */ c.rep.SetLength(n+1); bool seq1 = SS_BelowThresh(n+1, p.size()); ZZ_pContext context; context.save(); NTL_GEXEC_RANGE(seq1, n+1, first, last) context.restore(); ZZ ai, tmp, scratch; for (long i = first; i < last; i++) { ai = aa[i]; ZZ_p& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / N mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr, scratch); sub(tmp, p, ai); conv(ci, tmp); } else clear(ci); } NTL_GEXEC_RANGE_END c.normalize(); } // SSRatio computes how much bigger the SS modulus must be // to accomodate the necessary roots of unity. // This is useful in determining algorithm crossover points. double SSRatio(long na, long maxa, long nb, long maxb) { if (na <= 0 || nb <= 0) return 0; long n = na + nb; /* degree of the product */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long bound = 2 + NumBits(min(na, nb)) + maxa + maxb; long r = (bound >> l) + 1; long mr = r << l; // sqrt(2) trick long l1 = l; if (l1 >= 3) { long alt_l1 = l-1; long alt_r = (bound >> alt_l1) + 1; long alt_mr = alt_r << alt_l1; if (alt_mr < mr - mr/8) { l1 = alt_l1; r = alt_r; mr = alt_mr; } } return double(mr + 1)/double(bound); } static void conv(vec_zz_p& x, const ZZVec& a) { long i, n; n = a.length(); x.SetLength(n); VectorConv(n, x.elts(), a.elts()); } // Decide to use SSMul. static bool ChooseSS(long da, long maxbitsa, long db, long maxbitsb) { long k = ((maxbitsa+maxbitsb+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS)/2; double rat = SSRatio(da, maxbitsa, db, maxbitsb); #if 1 // I've made SSMul fully thread boosted, so I'm using // just one set of crossovers...FIXME: may need to tune this. return (k >= 13 && rat < 1.15) || (k >= 26 && rat < 1.30) || (k >= 53 && rat < 1.60) || (k >= 106 && rat < 1.80) || (k >= 212 && rat < 2.00); #else // This old code was based on the fact that SSMul was not // full thread boosted long nt = AvailableThreads(); if (nt == 1) { return (k >= 13 && rat < 1.15) || (k >= 26 && rat < 1.30) || (k >= 53 && rat < 1.60) || (k >= 106 && rat < 1.80) || (k >= 212 && rat < 2.00); } else if (nt == 2) { return (k >= 53 && rat < 1.10) || (k >= 106 && rat < 1.10) || (k >= 212 && rat < 1.40); } else if (nt == 3) { return (k >= 106 && rat < 1.05) || (k >= 212 && rat < 1.20); } else if (nt == 4) { return (k >= 106 && rat < 1.04) || (k >= 212 && rat < 1.10); } else if (nt <= 8) { return (k >= 212 && rat < 1.01); } else { return false; } #endif } void mul(ZZX& c, const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long maxa = MaxSize(a); long maxb = MaxSize(b); long k = min(maxa, maxb); long s = min(deg(a), deg(b)) + 1; // FIXME: I should have a way of setting all these crossovers // automatically if (s == 1 || (k == 1 && s < 40) || (k == 2 && s < 20) || (k == 3 && s < 10)) { PlainMul(c, a, b); return; } if (s < 80 || (k < 30 && s < 150)) { KarMul(c, a, b); return; } if (ChooseSS(deg(a), MaxBits(a), deg(b), MaxBits(b))) { SSMul(c, a, b); } else { HomMul(c, a, b); } } void SSSqr(ZZX& c, const ZZX& a) { long na = deg(a); if (na <= 0) { PlainSqr(c, a); return; } long n = na + na; /* degree of the product */ /* Choose m and r suitably */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long N = 1L << (l + 1); /* N = 2^{l+1} */ long bound = 2 + NumBits(na) + 2*MaxBits(a); /* Let r be minimal so that mr > bound */ long r = (bound >> l) + 1; long mr = r << l; // sqrt(2) trick long l1 = l; if (l1 >= 3) { long alt_l1 = l-1; long alt_r = (bound >> alt_l1) + 1; long alt_mr = alt_r << alt_l1; if (alt_mr < mr - mr/8) { l1 = alt_l1; r = alt_r; mr = alt_mr; } } /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); /* Make coefficients of a and b positive */ ZZVec aa; aa.SetSize(N, p.size()); for (long i = 0; i <= deg(a); i++) { if (sign(a.rep[i]) >= 0) { aa[i] = a.rep[i]; } else { add(aa[i], a.rep[i], p); } } long yn = SS_FFTRoundUp(n+1, l+1); /* N-point FFT's mod p */ fft_trunc(aa, yn, SS_FFTRoundUp(na+1, l+1), r, l+1, l1+1, p, mr); /* Pointwise multiplication aa := aa * bb mod p */ bool seq = SS_BelowThresh(yn, p.size()); NTL_GEXEC_RANGE(seq, yn, first, last) ZZ tmp, ai; for (long i = first; i < last; i++) { sqr(ai, aa[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } NTL_GEXEC_RANGE_END ifft_trunc(aa, yn, r, l+1, l1+1, p, mr); /* Retrieve c, dividing by N, and subtracting p where necessary */ c.rep.SetLength(n + 1); ZZ ai, tmp, scratch; for (long i = 0; i <= n; i++) { ai = aa[i]; ZZ& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / N mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr, scratch); sub(tmp, p, ai); if (NumBits(tmp) >= mr) { /* ci >= (p-1)/2 */ negate(ci, ai); /* ci = -ai = ci - p */ } else ci = tmp; } else clear(ci); } } void SSSqr(ZZ_pX& c, const ZZ_pX& a) { long na = deg(a); if (na <= 0) { PlainSqr(c, a); return; } long n = na + na; /* degree of the product */ /* Choose m and r suitably */ long l = NextPowerOfTwo(n + 1) - 1; /* 2^l <= n < 2^{l+1} */ long N = 1L << (l + 1); /* N = 2^{l+1} */ long bound = 2 + NumBits(na) + 2*NumBits(ZZ_p::modulus()); /* Let r be minimal so that mr > bound */ long r = (bound >> l) + 1; long mr = r << l; // sqrt(2) trick long l1 = l; if (l1 >= 3) { long alt_l1 = l-1; long alt_r = (bound >> alt_l1) + 1; long alt_mr = alt_r << alt_l1; if (alt_mr < mr - mr/8) { l1 = alt_l1; r = alt_r; mr = alt_mr; } } /* p := 2^{mr}+1 */ ZZ p; set(p); LeftShift(p, p, mr); add(p, p, 1); ZZVec aa; aa.SetSize(N, p.size()); for (long i = 0; i <= deg(a); i++) { aa[i] = rep(a.rep[i]); } long yn = SS_FFTRoundUp(n+1, l+1); /* N-point FFT's mod p */ fft_trunc(aa, yn, SS_FFTRoundUp(na+1, l+1), r, l+1, l1+1, p, mr); /* Pointwise multiplication aa := aa * bb mod p */ bool seq = SS_BelowThresh(yn, p.size()); NTL_GEXEC_RANGE(seq, yn, first, last) ZZ tmp, ai; for (long i = first; i < last; i++) { sqr(ai, aa[i]); if (NumBits(ai) > mr) { RightShift(tmp, ai, mr); trunc(ai, ai, mr); sub(ai, ai, tmp); if (sign(ai) < 0) { add(ai, ai, p); } } aa[i] = ai; } NTL_GEXEC_RANGE_END ifft_trunc(aa, yn, r, l+1, l1+1, p, mr); /* Retrieve c, dividing by N, and subtracting p where necessary */ c.rep.SetLength(n+1); bool seq1 = SS_BelowThresh(n+1, p.size()); ZZ_pContext context; context.save(); NTL_GEXEC_RANGE(seq1, n+1, first, last) context.restore(); ZZ ai, tmp, scratch; for (long i = first; i < last; i++) { ai = aa[i]; ZZ_p& ci = c.rep[i]; if (!IsZero(ai)) { /* ci = -ai * 2^{mr-l-1} = ai * 2^{-l-1} = ai / N mod p */ LeftRotate(ai, ai, mr - l - 1, p, mr, scratch); sub(tmp, p, ai); conv(ci, tmp); } else clear(ci); } NTL_GEXEC_RANGE_END c.normalize(); } void sqr(ZZX& c, const ZZX& a) { if (IsZero(a)) { clear(c); return; } long maxa = MaxSize(a); long k = maxa; long s = deg(a) + 1; if (s == 1 || (k == 1 && s < 50) || (k == 2 && s < 25) || (k == 3 && s < 25) || (k == 4 && s < 10)) { PlainSqr(c, a); return; } if (s < 80 || (k < 30 && s < 150)) { KarSqr(c, a); return; } if (ChooseSS(deg(a), MaxBits(a), deg(a), MaxBits(a))) { SSSqr(c, a); } else { HomSqr(c, a); } } void mul(ZZX& x, const ZZX& a, const ZZ& b) { ZZ t; long i, da; const ZZ *ap; ZZ* xp; if (IsZero(b)) { clear(x); return; } t = b; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); } void mul(ZZX& x, const ZZX& a, long b) { long i, da; const ZZ *ap; ZZ* xp; if (b == 0) { clear(x); return; } da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], b); } void diff(ZZX& x, const ZZX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void HomPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { if (IsZero(b)) ArithmeticError("division by zero"); long da = deg(a); long db = deg(b); if (da < db) { r = a; clear(q); return; } ZZ LC; LC = LeadCoeff(b); ZZ LC1; power(LC1, LC, da-db+1); long a_bound = NumBits(LC1) + MaxBits(a); LC1.kill(); long b_bound = MaxBits(b); zz_pBak bak; bak.save(); ZZX qq, rr; ZZ prod, t; set(prod); clear(qq); clear(rr); long i; long Qinstable, Rinstable; Qinstable = 1; Rinstable = 1; for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LC, p)) continue; zz_pX A, B, Q, R; conv(A, a); conv(B, b); if (!IsOne(LC)) { zz_p y; conv(y, LC); power(y, y, da-db+1); mul(A, A, y); } if (!Qinstable) { conv(Q, qq); mul(R, B, Q); sub(R, A, R); if (deg(R) >= db) Qinstable = 1; else Rinstable = CRT(rr, prod, R); } if (Qinstable) { DivRem(Q, R, A, B); t = prod; Qinstable = CRT(qq, t, Q); Rinstable = CRT(rr, prod, R); } if (!Qinstable && !Rinstable) { // stabilized...check if prod is big enough long bound1 = b_bound + MaxBits(qq) + NumBits(min(db, da-db)+1); long bound2 = MaxBits(rr); long bound = max(bound1, bound2); if (a_bound > bound) bound = a_bound; bound += 4; if (NumBits(prod) > bound) break; } } bak.restore(); q = qq; r = rr; } void HomPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { ZZX r; HomPseudoDivRem(q, r, a, b); } void HomPseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { ZZX q; HomPseudoDivRem(q, r, a, b); } void PlainPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { long da, db, dq, i, j, LCIsOne; const ZZ *bp; ZZ *qp; ZZ *xp; ZZ s, t; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); ZZ LC = bp[db]; LCIsOne = IsOne(LC); vec_ZZ x; x = a.rep; xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); if (!LCIsOne) { t = LC; for (i = dq-1; i >= 0; i--) { mul(xp[i], xp[i], t); if (i > 0) mul(t, t, LC); } } for (i = dq; i >= 0; i--) { t = xp[i+db]; qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, t, bp[j]); if (!LCIsOne) mul(xp[i+j], xp[i+j], LC); sub(xp[i+j], xp[i+j], s); } } if (!LCIsOne) { t = LC; for (i = 1; i <= dq; i++) { mul(qp[i], qp[i], t); if (i < dq) mul(t, t, LC); } } r.rep.SetLength(db); for (i = 0; i < db; i++) r.rep[i] = xp[i]; r.normalize(); } void PlainPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { ZZX r; PlainPseudoDivRem(q, r, a, b); } void PlainPseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { ZZX q; PlainPseudoDivRem(q, r, a, b); } void div(ZZX& q, const ZZX& a, long b) { if (b == 0) ArithmeticError("div: division by zero"); if (!divide(q, a, b)) ArithmeticError("DivRem: quotient undefined over ZZ"); } void div(ZZX& q, const ZZX& a, const ZZ& b) { if (b == 0) ArithmeticError("div: division by zero"); if (!divide(q, a, b)) ArithmeticError("DivRem: quotient undefined over ZZ"); } static void ConstDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZ& b) { if (b == 0) ArithmeticError("DivRem: division by zero"); if (!divide(q, a, b)) ArithmeticError("DivRem: quotient undefined over ZZ"); r = 0; } static void ConstRem(ZZX& r, const ZZX& a, const ZZ& b) { if (b == 0) ArithmeticError("rem: division by zero"); r = 0; } void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) ArithmeticError("DivRem: division by zero"); if (da < db) { r = a; q = 0; } else if (db == 0) { ConstDivRem(q, r, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoDivRem(q, r, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoDivRem(q, r, a, b1); negate(q, q); } else if (divide(q, a, b)) { r = 0; } else { ZZX q1, r1; ZZ m; PseudoDivRem(q1, r1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(q, q1, m)) ArithmeticError("DivRem: quotient not defined over ZZ"); if (!divide(r, r1, m)) ArithmeticError("DivRem: remainder not defined over ZZ"); } } void div(ZZX& q, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) ArithmeticError("div: division by zero"); if (da < db) { q = 0; } else if (db == 0) { div(q, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoDiv(q, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoDiv(q, a, b1); negate(q, q); } else if (divide(q, a, b)) { // nothing to do } else { ZZX q1; ZZ m; PseudoDiv(q1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(q, q1, m)) ArithmeticError("div: quotient not defined over ZZ"); } } void rem(ZZX& r, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db < 0) ArithmeticError("rem: division by zero"); if (da < db) { r = a; } else if (db == 0) { ConstRem(r, a, ConstTerm(b)); } else if (IsOne(LeadCoeff(b))) { PseudoRem(r, a, b); } else if (LeadCoeff(b) == -1) { ZZX b1; negate(b1, b); PseudoRem(r, a, b1); } else if (divide(a, b)) { r = 0; } else { ZZX r1; ZZ m; PseudoRem(r1, a, b); power(m, LeadCoeff(b), da-db+1); if (!divide(r, r1, m)) ArithmeticError("rem: remainder not defined over ZZ"); } } long HomDivide(ZZX& q, const ZZX& a, const ZZX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsZero(a)) { clear(q); return 1; } if (deg(b) == 0) { return divide(q, a, ConstTerm(b)); } if (deg(a) < deg(b)) return 0; ZZ ca, cb, cq; content(ca, a); content(cb, b); if (!divide(cq, ca, cb)) return 0; ZZX aa, bb; divide(aa, a, ca); divide(bb, b, cb); if (!divide(LeadCoeff(aa), LeadCoeff(bb))) return 0; if (!divide(ConstTerm(aa), ConstTerm(bb))) return 0; zz_pBak bak; bak.save(); ZZX qq; ZZ prod; set(prod); clear(qq); long res = 1; long Qinstable = 1; long a_bound = MaxBits(aa); long b_bound = MaxBits(bb); long i; for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(bb), p)) continue; zz_pX A, B, Q, R; conv(A, aa); conv(B, bb); if (!Qinstable) { conv(Q, qq); mul(R, B, Q); sub(R, A, R); if (deg(R) >= deg(B)) Qinstable = 1; else if (!IsZero(R)) { res = 0; break; } else mul(prod, prod, p); } if (Qinstable) { if (!divide(Q, A, B)) { res = 0; break; } Qinstable = CRT(qq, prod, Q); } if (!Qinstable) { // stabilized...check if prod is big enough long bound = b_bound + MaxBits(qq) + NumBits(min(deg(bb), deg(qq)) + 1); if (a_bound > bound) bound = a_bound; bound += 3; if (NumBits(prod) > bound) break; } } bak.restore(); if (res) mul(q, qq, cq); return res; } long HomDivide(const ZZX& a, const ZZX& b) { if (deg(b) == 0) { return divide(a, ConstTerm(b)); } else { ZZX q; return HomDivide(q, a, b); } } long PlainDivide(ZZX& qq, const ZZX& aa, const ZZX& bb) { if (IsZero(bb)) { if (IsZero(aa)) { clear(qq); return 1; } else return 0; } if (deg(bb) == 0) { return divide(qq, aa, ConstTerm(bb)); } long da, db, dq, i, j, LCIsOne; const ZZ *bp; ZZ *qp; ZZ *xp; ZZ s, t; da = deg(aa); db = deg(bb); if (da < db) { return 0; } ZZ ca, cb, cq; content(ca, aa); content(cb, bb); if (!divide(cq, ca, cb)) { return 0; } ZZX a, b, q; divide(a, aa, ca); divide(b, bb, cb); if (!divide(LeadCoeff(a), LeadCoeff(b))) return 0; if (!divide(ConstTerm(a), ConstTerm(b))) return 0; long coeff_bnd = MaxBits(a) + (NumBits(da+1)+1)/2 + (da-db); bp = b.rep.elts(); ZZ LC; LC = bp[db]; LCIsOne = IsOne(LC); xp = a.rep.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { if (!LCIsOne) { if (!divide(t, xp[i+db], LC)) return 0; } else t = xp[i+db]; if (NumBits(t) > coeff_bnd) return 0; qp[i] = t; for (j = db-1; j >= 0; j--) { mul(s, t, bp[j]); sub(xp[i+j], xp[i+j], s); } } for (i = 0; i < db; i++) if (!IsZero(xp[i])) return 0; mul(qq, q, cq); return 1; } long PlainDivide(const ZZX& a, const ZZX& b) { if (deg(b) == 0) return divide(a, ConstTerm(b)); else { ZZX q; return PlainDivide(q, a, b); } } long divide(ZZX& q, const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db <= 8 || da-db <= 8) return PlainDivide(q, a, b); else return HomDivide(q, a, b); } long divide(const ZZX& a, const ZZX& b) { long da = deg(a); long db = deg(b); if (db <= 8 || da-db <= 8) return PlainDivide(a, b); else return HomDivide(a, b); } long divide(ZZX& q, const ZZX& a, const ZZ& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (IsOne(b)) { q = a; return 1; } if (b == -1) { negate(q, a); return 1; } long n = a.rep.length(); vec_ZZ res(INIT_SIZE, n); long i; for (i = 0; i < n; i++) { if (!divide(res[i], a.rep[i], b)) return 0; } q.rep = res; return 1; } long divide(const ZZX& a, const ZZ& b) { if (IsZero(b)) return IsZero(a); if (IsOne(b) || b == -1) { return 1; } long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (!divide(a.rep[i], b)) return 0; } return 1; } long divide(ZZX& q, const ZZX& a, long b) { if (b == 0) { if (IsZero(a)) { clear(q); return 1; } else return 0; } if (b == 1) { q = a; return 1; } if (b == -1) { negate(q, a); return 1; } long n = a.rep.length(); vec_ZZ res(INIT_SIZE, n); long i; for (i = 0; i < n; i++) { if (!divide(res[i], a.rep[i], b)) return 0; } q.rep = res; return 1; } long divide(const ZZX& a, long b) { if (b == 0) return IsZero(a); if (b == 1 || b == -1) { return 1; } long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (!divide(a.rep[i], b)) return 0; } return 1; } void content(ZZ& d, const ZZX& f) { ZZ res; long i; clear(res); for (i = 0; i <= deg(f); i++) { GCD(res, res, f.rep[i]); if (IsOne(res)) break; } if (sign(LeadCoeff(f)) < 0) negate(res, res); d = res; } void PrimitivePart(ZZX& pp, const ZZX& f) { if (IsZero(f)) { clear(pp); return; } ZZ d; content(d, f); divide(pp, f, d); } static void BalCopy(ZZX& g, const zz_pX& G) { long p = zz_p::modulus(); long p2 = p >> 1; long n = G.rep.length(); long i; long t; g.rep.SetLength(n); for (i = 0; i < n; i++) { t = rep(G.rep[i]); if (t > p2) t = t - p; conv(g.rep[i], t); } } void GCD(ZZX& d, const ZZX& a, const ZZX& b) { if (IsZero(a)) { d = b; if (sign(LeadCoeff(d)) < 0) negate(d, d); return; } if (IsZero(b)) { d = a; if (sign(LeadCoeff(d)) < 0) negate(d, d); return; } ZZ c1, c2, c; ZZX f1, f2; content(c1, a); divide(f1, a, c1); content(c2, b); divide(f2, b, c2); GCD(c, c1, c2); ZZ ld; GCD(ld, LeadCoeff(f1), LeadCoeff(f2)); ZZX g, h, res; ZZ prod; set(prod); zz_pBak bak; bak.save(); long FirstTime = 1; long i; for (i = 0; ;i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(f1), p) || divide(LeadCoeff(f2), p)) continue; zz_pX G, F1, F2; zz_p LD; conv(F1, f1); conv(F2, f2); conv(LD, ld); GCD(G, F1, F2); mul(G, G, LD); if (deg(G) == 0) { set(res); break; } if (FirstTime || deg(G) < deg(g)) { FirstTime = 0; conv(prod, p); BalCopy(g, G); } else if (deg(G) > deg(g)) continue; else if (!CRT(g, prod, G)) { PrimitivePart(res, g); if (divide(f1, res) && divide(f2, res)) break; } } bak.restore(); mul(d, res, c); if (sign(LeadCoeff(d)) < 0) negate(d, d); } void trunc(ZZX& x, const ZZX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ* xp; const ZZ* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void LeftShift(ZZX& x, const ZZX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void RightShift(ZZX& x, const ZZX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void TraceVec(vec_ZZ& S, const ZZX& ff) { if (!IsOne(LeadCoeff(ff))) LogicError("TraceVec: bad args"); ZZX f; f = ff; long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ acc, t; S[0] = n; for (k = 1; k < n; k++) { mul(acc, f.rep[n-k], k); for (i = 1; i < k; i++) { mul(t, f.rep[n-i], S[k-i]); add(acc, acc, t); } negate(S[k], acc); } } static void EuclLength(ZZ& l, const ZZX& a) { long n = a.rep.length(); long i; ZZ sum, t; clear(sum); for (i = 0; i < n; i++) { sqr(t, a.rep[i]); add(sum, sum, t); } if (sum > 1) { SqrRoot(l, sum); add(l, l, 1); } else l = sum; } static long ResBound(const ZZX& a, const ZZX& b) { if (IsZero(a) || IsZero(b)) return 0; ZZ t1, t2, t; EuclLength(t1, a); EuclLength(t2, b); power(t1, t1, deg(b)); power(t2, t2, deg(a)); mul(t, t1, t2); return NumBits(t); } void resultant(ZZ& rres, const ZZX& a, const ZZX& b, long deterministic) { if (IsZero(a) || IsZero(b)) { clear(rres); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); long instable = 1; long bound = 2+ResBound(a, b); long gp_cnt = 0; ZZ res, prod; clear(res); set(prod); long i; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(res))); do { GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); } while (divide(LeadCoeff(a), P) || divide(LeadCoeff(b), P)); ZZ_p::init(P); ZZ_pX A, B; conv(A, a); conv(B, b); ZZ_p t; resultant(t, A, B); if (CRT(res, prod, rep(t), P)) instable = 1; else break; } zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(a), p) || divide(LeadCoeff(b), p)) continue; zz_pX A, B; conv(A, a); conv(B, b); zz_p t; resultant(t, A, B); instable = CRT(res, prod, rep(t), p); } rres = res; zbak.restore(); Zbak.restore(); } void MinPolyMod(ZZX& gg, const ZZX& a, const ZZX& f) { if (!IsOne(LeadCoeff(f)) || deg(f) < 1 || deg(a) >= deg(f)) LogicError("MinPolyMod: bad args"); if (IsZero(a)) { SetX(gg); return; } ZZ_pBak Zbak; Zbak.save(); zz_pBak zbak; zbak.save(); long n = deg(f); long instable = 1; long gp_cnt = 0; ZZ prod; ZZX g; clear(g); set(prod); long bound = -1; long i; for (i = 0; ; i++) { if (deg(g) == n) { if (bound < 0) bound = 2+CharPolyBound(a, f); if (NumBits(prod) > bound) break; } if (!instable && (deg(g) < n || (deg(g) == n && bound > 1000 && NumBits(prod) < 0.75*bound))) { // guarantees 2^{-80} error probability long plen = 90 + max( 2*NumBits(n) + NumBits(MaxBits(f)), max( NumBits(n) + NumBits(MaxBits(a)), NumBits(MaxBits(g)) )); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); ZZ_pX A, F, G; conv(A, a); conv(F, f); conv(G, g); ZZ_pXModulus FF; build(FF, F); ZZ_pX H; CompMod(H, G, A, FF); if (IsZero(H)) break; instable = 1; } zz_p::FFTInit(i); zz_pX A, F; conv(A, a); conv(F, f); zz_pXModulus FF; build(FF, F); zz_pX G; MinPolyMod(G, A, FF); if (deg(G) < deg(g)) continue; if (deg(G) > deg(g)) { clear(g); set(prod); } instable = CRT(g, prod, G); } gg = g; Zbak.restore(); zbak.restore(); } void XGCD(ZZ& rr, ZZX& ss, ZZX& tt, const ZZX& a, const ZZX& b, long deterministic) { ZZ r; resultant(r, a, b, deterministic); if (IsZero(r)) { clear(rr); return; } zz_pBak bak; bak.save(); long i; long instable = 1; ZZ tmp; ZZ prod; ZZX s, t; set(prod); clear(s); clear(t); for (i = 0; ; i++) { zz_p::FFTInit(i); long p = zz_p::modulus(); if (divide(LeadCoeff(a), p) || divide(LeadCoeff(b), p) || divide(r, p)) continue; zz_p R; conv(R, r); zz_pX D, S, T, A, B; conv(A, a); conv(B, b); if (!instable) { conv(S, s); conv(T, t); zz_pX t1, t2; mul(t1, A, S); mul(t2, B, T); add(t1, t1, t2); if (deg(t1) == 0 && ConstTerm(t1) == R) mul(prod, prod, p); else instable = 1; } if (instable) { XGCD(D, S, T, A, B); mul(S, S, R); mul(T, T, R); tmp = prod; long Sinstable = CRT(s, tmp, S); long Tinstable = CRT(t, prod, T); instable = Sinstable || Tinstable; } if (!instable) { long bound1 = NumBits(min(deg(a), deg(s)) + 1) + MaxBits(a) + MaxBits(s); long bound2 = NumBits(min(deg(b), deg(t)) + 1) + MaxBits(b) + MaxBits(t); long bound = 4 + max(NumBits(r), max(bound1, bound2)); if (NumBits(prod) > bound) break; } } rr = r; ss = s; tt = t; bak.restore(); } void NormMod(ZZ& x, const ZZX& a, const ZZX& f, long deterministic) { if (!IsOne(LeadCoeff(f)) || deg(a) >= deg(f) || deg(f) <= 0) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } resultant(x, f, a, deterministic); } void TraceMod(ZZ& res, const ZZX& a, const ZZX& f) { if (!IsOne(LeadCoeff(f)) || deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); vec_ZZ S; TraceVec(S, f); InnerProduct(res, S, a.rep); } void discriminant(ZZ& d, const ZZX& a, long deterministic) { long m = deg(a); if (m < 0) { clear(d); return; } ZZX a1; ZZ res; diff(a1, a); resultant(res, a, a1, deterministic); if (!divide(res, res, LeadCoeff(a))) LogicError("discriminant: inexact division"); m = m & 3; if (m >= 2) negate(res, res); d = res; } void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0 || !IsOne(LeadCoeff(f))) LogicError("MulMod: bad args"); ZZX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZX& x, const ZZX& a, const ZZX& f) { if (deg(a) >= deg(f) || deg(f) == 0 || !IsOne(LeadCoeff(f))) LogicError("MulMod: bad args"); ZZX t; sqr(t, a); rem(x, t, f); } static void MulByXModAux(ZZX& h, const ZZX& a, const ZZX& f) { long i, n, m; ZZ* hh; const ZZ *aa, *ff; ZZ t, z; n = deg(f); m = deg(a); if (m >= n || n == 0 || !IsOne(LeadCoeff(f))) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZX& h, const ZZX& a, const ZZX& f) { if (&h == &f) { ZZX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } static void EuclLength1(ZZ& l, const ZZX& a) { long n = a.rep.length(); long i; ZZ sum, t; clear(sum); for (i = 0; i < n; i++) { sqr(t, a.rep[i]); add(sum, sum, t); } abs(t, ConstTerm(a)); mul(t, t, 2); add(t, t, 1); add(sum, sum, t); if (sum > 1) { SqrRoot(l, sum); add(l, l, 1); } else l = sum; } long CharPolyBound(const ZZX& a, const ZZX& f) // This computes a bound on the size of the // coefficients of the characterstic polynomial. // It uses the characterization of the char poly as // resultant_y(f(y), x-a(y)), and then interpolates this // through complex primimitive (deg(f)+1)-roots of unity. { if (IsZero(a) || IsZero(f)) LogicError("CharPolyBound: bad args"); ZZ t1, t2, t; EuclLength1(t1, a); EuclLength(t2, f); power(t1, t1, deg(f)); power(t2, t2, deg(a)); mul(t, t1, t2); return NumBits(t); } void SetCoeff(ZZX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZRegister(aa); conv(aa, a); SetCoeff(x, i, aa); } } void CopyReverse(ZZX& x, const ZZX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ* ap = a.rep.elts(); ZZ* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void reverse(ZZX& x, const ZZX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { ZZX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n) { ZZX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(ZZX& x, const ZZX& a, long n) { ZZX t; sqr(t, a); trunc(x, t, n); } void NewtonInvTrunc(ZZX& c, const ZZX& a, long e) { ZZ x; if (ConstTerm(a) == 1) x = 1; else if (ConstTerm(a) == -1) x = -1; else ArithmeticError("InvTrunc: non-invertible constant term"); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); ZZX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(ZZX& c, const ZZX& a, long e) { if (e < 0) LogicError("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) ResourceError("overflow in InvTrunc"); NewtonInvTrunc(c, a, e); } NTL_END_IMPL ntl-11.5.1/src/ZZXCharPoly.cpp0000644417616742025610000000235514064716022017612 0ustar gid-shoupvpug-gid-shoupv#include NTL_START_IMPL void CharPolyMod(ZZX& gg, const ZZX& a, const ZZX& f, long deterministic) { if (!IsOne(LeadCoeff(f)) || deg(f) < 1 || deg(a) >= deg(f)) LogicError("CharPolyMod: bad args"); if (IsZero(a)) { clear(gg); SetCoeff(gg, deg(f)); return; } long bound = 2 + CharPolyBound(a, f); long gp_cnt = 0; zz_pBak bak; bak.save(); ZZ_pBak bak1; bak1.save(); ZZX g; ZZ prod; clear(g); set(prod); long i; long instable = 1; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { long plen = 90 + NumBits(max(bound, MaxBits(g))); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); ZZ_pX G, A, F; conv(A, a); conv(F, f); CharPolyMod(G, A, F); if (CRT(g, prod, G)) instable = 1; else break; } zz_p::FFTInit(i); zz_pX G, A, F; conv(A, a); conv(F, f); CharPolyMod(G, A, F); instable = CRT(g, prod, G); } gg = g; bak.restore(); bak1.restore(); } NTL_END_IMPL ntl-11.5.1/src/ZZXFactoring.cpp0000644417616742025610000023076614064716022020016 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include #include NTL_START_IMPL NTL_CHEAP_THREAD_LOCAL long ZZXFac_van_Hoeij = 1; static NTL_CHEAP_THREAD_LOCAL long ok_to_abandon = 0; struct LocalInfoT { long n; long NumPrimes; long NumFactors; vec_long p; vec_vec_long pattern; ZZ PossibleDegrees; PrimeSeq s; }; static void mul(ZZ_pX& x, vec_ZZ_pX& a) // this performs multiplications in close-to-optimal order, // and kills a in the process { long n = a.length(); // first, deal with some trivial cases if (n == 0) { set(x); a.kill(); return; } else if (n == 1) { x = a[0]; a.kill(); return; } long i, j; // assume n > 1 and all a[i]'s are nonzero // sort into non-increasing degrees for (i = 1; i <= n - 1; i++) for (j = 0; j <= n - i - 1; j++) if (deg(a[j]) < deg(a[j+1])) swap(a[j], a[j+1]); ZZ_pX g; while (n > 1) { // replace smallest two poly's by their product mul(g, a[n-2], a[n-1]); a[n-2].kill(); a[n-1].kill(); swap(g, a[n-2]); n--; // re-establish order i = n-1; while (i > 0 && deg(a[i-1]) < deg(a[i])) { swap(a[i-1], a[i]); i--; } } x = a[0]; a[0].kill(); a.SetLength(0); } void mul(ZZX& x, const vec_pair_ZZX_long& a) { long l = a.length(); ZZX res; long i, j; set(res); for (i = 0; i < l; i++) for (j = 0; j < a[i].b; j++) mul(res, res, a[i].a); x = res; } void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& ff) // input is primitive { ZZX f = ff; ZZX d, v, w, s, t1; long i; u.SetLength(0); if (deg(f) <= 0) return; diff(t1, f); GCD(d, f, t1); if (deg(d) == 0) { append(u, cons(f, 1L)); return; } divide(v, f, d); divide(w, t1, d); i = 0; for (;;) { i = i + 1; diff(t1, v); sub(s, w, t1); if (IsZero(s)) { if (deg(v) != 0) append(u, cons(v, i)); return; } GCD(d, v, s); divide(v, v, d); divide(w, s, d); if (deg(d) != 0) append(u, cons(d, i)); } } static void HenselLift(ZZX& Gout, ZZX& Hout, ZZX& Aout, ZZX& Bout, const ZZX& f, const ZZX& g, const ZZX& h, const ZZX& a, const ZZX& b, const ZZ& p) { ZZX c, g1, h1, G, H, A, B; mul(c, g, h); sub(c, f, c); if (!divide(c, c, p)) LogicError("inexact division"); ZZ_pX cc, gg, hh, aa, bb, tt, gg1, hh1; conv(cc, c); conv(gg, g); conv(hh, h); conv(aa, a); conv(bb, b); ZZ_pXModulus GG; ZZ_pXModulus HH; build(GG, gg); build(HH, hh); ZZ_pXMultiplier AA; ZZ_pXMultiplier BB; build(AA, aa, HH); build(BB, bb, GG); rem(gg1, cc, GG); MulMod(gg1, gg1, BB, GG); rem(hh1, cc, HH); MulMod(hh1, hh1, AA, HH); conv(g1, gg1); mul(g1, g1, p); add(G, g, g1); conv(h1, hh1); mul(h1, h1, p); add(H, h, h1); /* lift inverses */ ZZX t1, t2, r; mul(t1, a, G); mul(t2, b, H); add(t1, t1, t2); add(t1, t1, -1); negate(t1, t1); if (!divide(r, t1, p)) LogicError("inexact division"); ZZ_pX rr, aa1, bb1; conv(rr, r); rem(aa1, rr, HH); MulMod(aa1, aa1, AA, HH); rem(bb1, rr, GG); MulMod(bb1, bb1, BB, GG); ZZX a1, b1; conv(a1, aa1); mul(a1, a1, p); add(A, a, a1); conv(b1, bb1); mul(b1, b1, p); add(B, b, b1); Gout = G; Hout = H; Aout = A; Bout = B; } static void HenselLift1(ZZX& Gout, ZZX& Hout, const ZZX& f, const ZZX& g, const ZZX& h, const ZZX& a, const ZZX& b, const ZZ& p) { ZZX c, g1, h1, G, H; mul(c, g, h); sub(c, f, c); if (!divide(c, c, p)) LogicError("inexact division"); ZZ_pX cc, gg, hh, aa, bb, tt, gg1, hh1; conv(cc, c); conv(gg, g); conv(hh, h); conv(aa, a); conv(bb, b); ZZ_pXModulus GG; ZZ_pXModulus HH; build(GG, gg); build(HH, hh); rem(gg1, cc, GG); MulMod(gg1, gg1, bb, GG); rem(hh1, cc, HH); MulMod(hh1, hh1, aa, HH); conv(g1, gg1); mul(g1, g1, p); add(G, g, g1); conv(h1, hh1); mul(h1, h1, p); add(H, h, h1); Gout = G; Hout = H; } static void BuildTree(vec_long& link, vec_ZZX& v, vec_ZZX& w, const vec_zz_pX& a) { long k = a.length(); if (k < 2) LogicError("bad arguments to BuildTree"); vec_zz_pX V, W; V.SetLength(2*k-2); W.SetLength(2*k-2); link.SetLength(2*k-2); long i, j, s; long minp, mind; for (i = 0; i < k; i++) { V[i] = a[i]; link[i] = -(i+1); } for (j = 0; j < 2*k-4; j += 2) { minp = j; mind = deg(V[j]); for (s = j+1; s < i; s++) if (deg(V[s]) < mind) { minp = s; mind = deg(V[s]); } swap(V[j], V[minp]); swap(link[j], link[minp]); minp = j+1; mind = deg(V[j+1]); for (s = j+2; s < i; s++) if (deg(V[s]) < mind) { minp = s; mind = deg(V[s]); } swap(V[j+1], V[minp]); swap(link[j+1], link[minp]); mul(V[i], V[j], V[j+1]); link[i] = j; i++; } zz_pX d; for (j = 0; j < 2*k-2; j += 2) { XGCD(d, W[j], W[j+1], V[j], V[j+1]); if (!IsOne(d)) LogicError("relatively prime polynomials expected"); } v.SetLength(2*k-2); for (j = 0; j < 2*k-2; j++) conv(v[j], V[j]); w.SetLength(2*k-2); for (j = 0; j < 2*k-2; j++) conv(w[j], W[j]); } static void RecTreeLift(const vec_long& link, vec_ZZX& v, vec_ZZX& w, const ZZ& p, const ZZX& f, long j, long inv) { if (j < 0) return; if (inv) HenselLift(v[j], v[j+1], w[j], w[j+1], f, v[j], v[j+1], w[j], w[j+1], p); else HenselLift1(v[j], v[j+1], f, v[j], v[j+1], w[j], w[j+1], p); RecTreeLift(link, v, w, p, v[j], link[j], inv); RecTreeLift(link, v, w, p, v[j+1], link[j+1], inv); } static void TreeLift(const vec_long& link, vec_ZZX& v, vec_ZZX& w, long e0, long e1, const ZZX& f, long inv) // lift from p^{e0} to p^{e1} { ZZ p0, p1; power(p0, zz_p::modulus(), e0); power(p1, zz_p::modulus(), e1-e0); ZZ_pBak bak; bak.save(); ZZ_p::init(p1); RecTreeLift(link, v, w, p0, f, v.length()-2, inv); bak.restore(); } void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose) { long k = a.length(); long i; if (k < 2 || e < 1 || NTL_OVERFLOW(e, 1, 0)) LogicError("MultiLift: bad args"); if (!IsOne(LeadCoeff(f))) LogicError("MultiLift: bad args"); for (i = 0; i < a.length(); i++) if (!IsOne(LeadCoeff(a[i]))) LogicError("MultiLift: bad args"); if (e == 1) { A.SetLength(k); for (i = 0; i < k; i++) conv(A[i], a[i]); return; } vec_long E; append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long l = E.length(); vec_ZZX v, w; vec_long link; double t; if (verbose) { cerr << "building tree..."; t = GetTime(); } BuildTree(link, v, w, a); if (verbose) cerr << (GetTime()-t) << "\n"; for (i = l-1; i > 0; i--) { if (verbose) { cerr << "lifting to " << E[i-1] << "..."; t = GetTime(); } TreeLift(link, v, w, E[i], E[i-1], f, i != 1); if (verbose) cerr << (GetTime()-t) << "\n"; } A.SetLength(k); for (i = 0; i < 2*k-2; i++) { long t = link[i]; if (t < 0) A[-(t+1)] = v[i]; } } static void inplace_rev(ZZX& f) { long n = deg(f); long i, j; i = 0; j = n; while (i < j) { swap(f.rep[i], f.rep[j]); i++; j--; } f.normalize(); } NTL_CHEAP_THREAD_LOCAL long ZZXFac_InitNumPrimes = 7; NTL_CHEAP_THREAD_LOCAL long ZZXFac_MaxNumPrimes = 50; static void RecordPattern(vec_long& pat, vec_pair_zz_pX_long& fac) { long n = pat.length()-1; long i; for (i = 0; i <= n; i++) pat[i] = 0; long k = fac.length(); for (i = 0; i < k; i++) { long d = fac[i].b; long m = deg(fac[i].a)/d; pat[d] = m; } } static long NumFactors(const vec_long& pat) { long n = pat.length()-1; long i; long res = 0; for (i = 0; i <= n; i++) res += pat[i]; return res; } static void CalcPossibleDegrees(ZZ& pd, const vec_long& pat) { long n = pat.length()-1; set(pd); long d, j; ZZ t1; for (d = 1; d <= n; d++) for (j = 0; j < pat[d]; j++) { LeftShift(t1, pd, d); bit_or(pd, pd, t1); } } static void CalcPossibleDegrees(vec_ZZ& S, const vec_ZZ_pX& fac, long k) // S[i] = possible degrees of the product of any subset of size k // among fac[i...], encoded as a bit vector. { long r = fac.length(); S.SetLength(r); if (r == 0) return; if (k < 1 || k > r) LogicError("CalcPossibleDegrees: bad args"); long i, l; ZZ old, t1; set(S[r-1]); LeftShift(S[r-1], S[r-1], deg(fac[r-1])); for (i = r-2; i >= 0; i--) { set(t1); LeftShift(t1, t1, deg(fac[i])); bit_or(S[i], t1, S[i+1]); } for (l = 2; l <= k; l++) { old = S[r-l]; LeftShift(S[r-l], S[r-l+1], deg(fac[r-l])); for (i = r-l-1; i >= 0; i--) { LeftShift(t1, old, deg(fac[i])); old = S[i]; bit_or(S[i], S[i+1], t1); } } } static vec_zz_pX * SmallPrimeFactorization(LocalInfoT& LocalInfo, const ZZX& f, long verbose) { long n = deg(f); long i; double t; LocalInfo.n = n; long& NumPrimes = LocalInfo.NumPrimes; NumPrimes = 0; LocalInfo.NumFactors = 0; // some sanity checking... if (ZZXFac_InitNumPrimes < 1 || ZZXFac_InitNumPrimes > 10000) LogicError("bad ZZXFac_InitNumPrimes"); if (ZZXFac_MaxNumPrimes < ZZXFac_InitNumPrimes || ZZXFac_MaxNumPrimes > 10000) LogicError("bad ZZXFac_MaxNumPrimes"); LocalInfo.p.SetLength(ZZXFac_InitNumPrimes); LocalInfo.pattern.SetLength(ZZXFac_InitNumPrimes); // set bits 0..n of LocalInfo.PossibleDegrees SetBit(LocalInfo.PossibleDegrees, n+1); add(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, -1); long minr = n+1; long irred = 0; UniquePtr bestfac; UniquePtr besth; UniquePtr spfactors; zz_pContext bestp; long bestp_index; long maxroot = NextPowerOfTwo(deg(f))+1; for (; NumPrimes < ZZXFac_InitNumPrimes;) { long p = LocalInfo.s.next(); if (!p) ResourceError("out of small primes"); if (divide(LeadCoeff(f), p)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } zz_p::init(p, maxroot); zz_pX ff, ffp, d; conv(ff, f); MakeMonic(ff); diff(ffp, ff); GCD(d, ffp, ff); if (!IsOne(d)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } if (verbose) { cerr << "factoring mod " << p << "..."; t = GetTime(); } vec_pair_zz_pX_long thisfac; zz_pX thish; SFCanZass1(thisfac, thish, ff, 0); LocalInfo.p[NumPrimes] = p; vec_long& pattern = LocalInfo.pattern[NumPrimes]; pattern.SetLength(n+1); RecordPattern(pattern, thisfac); long r = NumFactors(pattern); if (verbose) { cerr << (GetTime()-t) << "\n"; cerr << "degree sequence: "; for (i = 0; i <= n; i++) if (pattern[i]) { cerr << pattern[i] << "*" << i << " "; } cerr << "\n"; } if (r == 1) { irred = 1; break; } // update admissibility info ZZ pd; CalcPossibleDegrees(pd, pattern); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); if (weight(LocalInfo.PossibleDegrees) == 2) { irred = 1; break; } if (r < minr) { minr = r; bestfac.make(thisfac); besth.make(thish); bestp.save(); bestp_index = NumPrimes; } NumPrimes++; } if (!irred) { // remove best prime from LocalInfo swap(LocalInfo.pattern[bestp_index], LocalInfo.pattern[NumPrimes-1]); LocalInfo.p[bestp_index] = LocalInfo.p[NumPrimes-1]; NumPrimes--; bestp.restore(); spfactors.make(); if (verbose) { cerr << "p = " << zz_p::modulus() << ", completing factorization..."; t = GetTime(); } SFCanZass2(*spfactors, *bestfac, *besth, 0); if (verbose) { cerr << (GetTime()-t) << "\n"; } } return spfactors.release(); } static long ConstTermTest(const vec_ZZ_pX& W, const vec_long& I, const ZZ& ct, const ZZ_p& lc, vec_ZZ_p& prod, long& ProdLen) { long k = I.length(); ZZ_p t; ZZ t1, t2; long i; if (ProdLen == 0) { mul(prod[0], lc, ConstTerm(W[I[0]])); ProdLen++; } for (i = ProdLen; i < k; i++) mul(prod[i], prod[i-1], ConstTerm(W[I[i]])); ProdLen = k-1; // should make this a routine in ZZ_p t1 = rep(prod[k-1]); RightShift(t2, ZZ_p::modulus(), 1); if (t1 > t2) sub(t1, t1, ZZ_p::modulus()); return divide(ct, t1); } static void BalCopy(ZZX& g, const ZZ_pX& G) { const ZZ& p = ZZ_p::modulus(); ZZ p2, t; RightShift(p2, p, 1); long n = G.rep.length(); long i; g.rep.SetLength(n); for (i = 0; i < n; i++) { t = rep(G.rep[i]); if (t > p2) sub(t, t, p); g.rep[i] = t; } } static void mul(ZZ_pX& g, const vec_ZZ_pX& W, const vec_long& I) { vec_ZZ_pX w; long k = I.length(); w.SetLength(k); long i; for (i = 0; i < k; i++) w[i] = W[I[i]]; mul(g, w); } static void InvMul(ZZ_pX& g, const vec_ZZ_pX& W, const vec_long& I) { vec_ZZ_pX w; long k = I.length(); long r = W.length(); w.SetLength(r-k); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else w[j-i] = W[j]; } mul(g, w); } static void RemoveFactors(vec_ZZ_pX& W, const vec_long& I) { long k = I.length(); long r = W.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } W.SetLength(r-k); } static void unpack(vec_long& x, const ZZ& a, long n) { x.SetLength(n+1); long i; for (i = 0; i <= n; i++) x[i] = bit(a, i); } static void SubPattern(vec_long& p1, const vec_long& p2) { long l = p1.length(); if (p2.length() != l) LogicError("SubPattern: bad args"); long i; for (i = 0; i < l; i++) { p1[i] -= p2[i]; if (p1[i] < 0) LogicError("SubPattern: internal error"); } } static void UpdateLocalInfo(LocalInfoT& LocalInfo, vec_ZZ& pdeg, const vec_ZZ_pX& W, const vec_ZZX& factors, const ZZX& f, long k, long verbose) { static NTL_CHEAP_THREAD_LOCAL long cnt = 0; if (verbose) { cnt = (cnt + 1) % 100; if (!cnt) cerr << "#"; } double t; long i, j; if (LocalInfo.NumFactors < factors.length()) { zz_pBak bak; bak.save(); vec_long pattern; pattern.SetLength(LocalInfo.n+1); ZZ pd; if (verbose) { cerr << "updating local info..."; t = GetTime(); } for (i = 0; i < LocalInfo.NumPrimes; i++) { zz_p::init(LocalInfo.p[i], NextPowerOfTwo(LocalInfo.n)+1); for (j = LocalInfo.NumFactors; j < factors.length(); j++) { vec_pair_zz_pX_long thisfac; zz_pX thish; zz_pX ff; conv(ff, factors[j]); MakeMonic(ff); SFCanZass1(thisfac, thish, ff, 0); RecordPattern(pattern, thisfac); SubPattern(LocalInfo.pattern[i], pattern); } CalcPossibleDegrees(pd, LocalInfo.pattern[i]); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); } bak.restore(); LocalInfo.NumFactors = factors.length(); CalcPossibleDegrees(pdeg, W, k); if (verbose) cerr << (GetTime()-t) << "\n"; } if (!ZZXFac_van_Hoeij && LocalInfo.NumPrimes + 1 < ZZXFac_MaxNumPrimes) { if (verbose) cerr << "adding a prime\n"; zz_pBak bak; bak.save(); for (;;) { long p = LocalInfo.s.next(); if (!p) ResourceError("UpdateLocalInfo: out of primes"); if (divide(LeadCoeff(f), p)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } zz_p::init(p, NextPowerOfTwo(deg(f))+1); zz_pX ff, ffp, d; conv(ff, f); MakeMonic(ff); diff(ffp, ff); GCD(d, ffp, ff); if (!IsOne(d)) { if (verbose) cerr << "skipping " << p << "\n"; continue; } vec_pair_zz_pX_long thisfac; zz_pX thish; if (verbose) { cerr << "factoring mod " << p << "..."; t = GetTime(); } SFCanZass1(thisfac, thish, ff, 0); LocalInfo.p.SetLength(LocalInfo.NumPrimes+1); LocalInfo.pattern.SetLength(LocalInfo.NumPrimes+1); LocalInfo.p[LocalInfo.NumPrimes] = p; vec_long& pattern = LocalInfo.pattern[LocalInfo.NumPrimes]; pattern.SetLength(LocalInfo.n+1); RecordPattern(pattern, thisfac); if (verbose) { cerr << (GetTime()-t) << "\n"; cerr << "degree sequence: "; for (i = 0; i <= LocalInfo.n; i++) if (pattern[i]) { cerr << pattern[i] << "*" << i << " "; } cerr << "\n"; } ZZ pd; CalcPossibleDegrees(pd, pattern); bit_and(LocalInfo.PossibleDegrees, LocalInfo.PossibleDegrees, pd); LocalInfo.NumPrimes++; break; } bak.restore(); } } const int ZZX_OVERLIFT = NTL_BITS_PER_LONG; // number of bits by which we "overlift"....this enables, in particular, // the "n-1" test. // Must lie in the range 4..NTL_BITS_PER_LONG. #define EXTRA_BITS (1) // Any small number, like 1, 2 or 3, should be OK. static void CardinalitySearch(vec_ZZX& factors, ZZX& f, vec_ZZ_pX& W, LocalInfoT& LocalInfo, long k, long bnd, long verbose) { double start_time, end_time; if (verbose) { start_time = GetTime(); cerr << "\n************ "; cerr << "start cardinality " << k << "\n"; } vec_long I, D; I.SetLength(k); D.SetLength(k); long r = W.length(); vec_ZZ_p prod; prod.SetLength(k); long ProdLen; vec_ZZ pdeg; CalcPossibleDegrees(pdeg, W, k); ZZ pd; vec_long upd; long i, state; long cnt = 0; ZZ ct; mul(ct, ConstTerm(f), LeadCoeff(f)); ZZ_p lc; conv(lc, LeadCoeff(f)); ZZ_pX gg; ZZX g, h; I[0] = 0; while (I[0] <= r-k) { bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); D[0] = deg(W[I[0]]); i = 1; state = 0; ProdLen = 0; for (;;) { if (i < ProdLen) ProdLen = i; if (i == k) { // process indices I[0], ..., I[k-1] if (cnt > 2000000) { cnt = 0; UpdateLocalInfo(LocalInfo, pdeg, W, factors, f, k, verbose); bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); } state = 1; // default continuation state if (!upd[D[k-1]]) { i--; cnt++; continue; } if (!ConstTermTest(W, I, ct, lc, prod, ProdLen)) { i--; cnt += 100; continue; } if (verbose) { cerr << "+"; } cnt += 1000; if (2*D[k-1] <= deg(f)) { mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { i--; continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { i--; continue; } // factor found! append(factors, g); if (verbose) { cerr << "degree " << deg(g) << " factor found\n"; } f = h; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } else { InvMul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { i--; continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { i--; continue; } // factor found! append(factors, h); if (verbose) { cerr << "degree " << deg(h) << " factor found\n"; } f = g; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } RemoveFactors(W, I); r = W.length(); cnt = 0; if (2*k > r) goto done; else break; } else if (state == 0) { I[i] = I[i-1] + 1; D[i] = D[i-1] + deg(W[I[i]]); i++; } else { // state == 1 I[i]++; if (i == 0) break; if (I[i] > r-k+i) i--; else { D[i] = D[i-1] + deg(W[I[i]]); i++; state = 0; } } } } done: if (verbose) { end_time = GetTime(); cerr << "\n************ "; cerr << "end cardinality " << k << "\n"; cerr << "time: " << (end_time-start_time) << "\n"; } } typedef unsigned long TBL_T; #if (NTL_BITS_PER_LONG >= 64) // for 64-bit machines #define TBL_MSK (63) #define TBL_SHAMT (6) #else // for 32-bit machines #define TBL_MSK (31) #define TBL_SHAMT (5) #endif #if 0 // recursive version static void RecInitTab(TBL_T ***lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab, unsigned long sum, long card, long j) { if (j >= i || card >= k-1) { if (card > 1) { long shamt = shamt_tab[i][card]; unsigned long index1 = ((-sum) >> shamt); lookup_tab[i][card][index1 >> TBL_SHAMT] |= (1UL << (index1 & TBL_MSK)); unsigned long index2 = ((-sum+thresh1) >> shamt); if (index1 != index2) lookup_tab[i][card][index2 >> TBL_SHAMT] |= (1UL << (index2 & TBL_MSK)); } return; } RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, sum, card, j+1); RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, sum+ratio[r-1-j], card+1, j+1); } static void DoInitTab(TBL_T ***lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, long **shamt_tab) { RecInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab, 0, 0, 0); } #else // iterative version typedef Vec< Vec< Vec< TBL_T > > > lookup_tab_t; typedef Vec< Vec > shamt_tab_t; static void DoInitTab(lookup_tab_t& lookup_tab, long i, const vec_ulong& ratio, long r, long k, unsigned long thresh1, shamt_tab_t& shamt_tab) { vec_long sum_vec, card_vec, location_vec; sum_vec.SetLength(i+1); card_vec.SetLength(i+1); location_vec.SetLength(i+1); long j = 0; sum_vec[0] = 0; card_vec[0] = 0; unsigned long sum; long card, location; location = 0; while (j >= 0) { sum = sum_vec[j]; card = card_vec[j]; switch (location) { case 0: if (j >= i || card >= k-1) { if (card > 1) { long shamt = shamt_tab[i][card]; unsigned long index1 = ((-sum) >> shamt); lookup_tab[i][card][index1 >> TBL_SHAMT] |= (1UL << (index1 & TBL_MSK)); unsigned long index2 = ((-sum+thresh1) >> shamt); if (index1 != index2) lookup_tab[i][card][index2 >> TBL_SHAMT] |= (1UL << (index2 & TBL_MSK)); } location = location_vec[j]; j--; continue; } sum_vec[j+1] = sum; card_vec[j+1] = card; location_vec[j+1] = 1; j++; location = 0; continue; case 1: sum_vec[j+1] = sum+ratio[r-1-j]; card_vec[j+1] = card+1; location_vec[j+1] = 2; j++; location = 0; continue; case 2: location = location_vec[j]; j--; continue; } } } #endif static void InitTab(lookup_tab_t& lookup_tab, const vec_ulong& ratio, long r, long k, unsigned long thresh1, shamt_tab_t& shamt_tab, long pruning) { long i, j, t; if (pruning) { for (i = 2; i <= pruning; i++) { long len = min(k-1, i); for (j = 2; j <= len; j++) { long ub = (((1L << (NTL_BITS_PER_LONG-shamt_tab[i][j])) + TBL_MSK) >> TBL_SHAMT); for (t = 0; t < ub; t++) lookup_tab[i][j][t] = 0; } DoInitTab(lookup_tab, i, ratio, r, k, thresh1, shamt_tab); } } } static void RatioInit1(vec_ulong& ratio, const vec_ZZ_pX& W, const ZZ_p& lc, long pruning, lookup_tab_t& lookup_tab, vec_vec_ulong& pair_ratio, long k, unsigned long thresh1, shamt_tab_t& shamt_tab) { long r = W.length(); long i, j; ZZ_p a; ZZ p; p = ZZ_p::modulus(); ZZ aa; for (i = 0; i < r; i++) { long m = deg(W[i]); mul(a, W[i].rep[m-1], lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); ratio[i] = to_ulong(aa); } InitTab(lookup_tab, ratio, r, k, thresh1, shamt_tab, pruning); for (i = 0; i < r; i++) for (j = 0; j < i; j++) { mul(a, W[i].rep[deg(W[i])-1], W[j].rep[deg(W[j])-1]); mul(a, a, lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); pair_ratio[i][j] = to_ulong(aa); } for (i = 0; i < r; i++) { long m = deg(W[i]); if (m >= 2) { mul(a, W[i].rep[m-2], lc); LeftShift(aa, rep(a), NTL_BITS_PER_LONG); div(aa, aa, p); pair_ratio[i][i] = to_ulong(aa); } else pair_ratio[i][i] = 0; } } static long SecondOrderTest(const vec_long& I_vec, const vec_vec_ulong& pair_ratio_vec, vec_ulong& sum_stack_vec, long& SumLen) { long k = I_vec.length(); const long *I = I_vec.elts(); unsigned long *sum_stack = sum_stack_vec.elts(); unsigned long sum, thresh1; if (SumLen == 0) { unsigned long epsilon = (1UL << (NTL_BITS_PER_LONG-ZZX_OVERLIFT)); unsigned long delta = (unsigned long) ((k*(k+1)) >> 1); unsigned long thresh = epsilon + delta; thresh1 = (epsilon << 1) + delta; sum = thresh; sum_stack[k] = thresh1; } else { sum = sum_stack[SumLen-1]; thresh1 = sum_stack[k]; } long i, j; for (i = SumLen; i < k; i++) { const unsigned long *p = pair_ratio_vec[I[i]].elts(); for (j = 0; j <= i; j++) { sum += p[I[j]]; } sum_stack[i] = sum; } SumLen = k-1; return (sum <= thresh1); } static ZZ choose_fn(long r, long k) { ZZ a, b; a = 1; b = 1; long i; for (i = 0; i < k; i++) { a *= r-i; b *= k-i; } return a/b; } static void PrintInfo(const char *s, const ZZ& a, const ZZ& b) { cerr << s << a << " / " << b << " = "; double x = to_double(a)/to_double(b); if (x == 0) cerr << "0"; else { int n; double f; f = frexp(x, &n); cerr << f << "*2^" << n; } cerr << "\n"; } static void RemoveFactors1(vec_long& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } } static void RemoveFactors1(vec_vec_long& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } for (i = 0; i < r-k; i++) RemoveFactors1(W[i], I, r); } static void RemoveFactors1(vec_ulong& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else _ntl_swap(W[j-i], W[j]); } } static void RemoveFactors1(vec_vec_ulong& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } for (i = 0; i < r-k; i++) RemoveFactors1(W[i], I, r); } static void RemoveFactors1(vec_ZZ_p& W, const vec_long& I, long r) { long k = I.length(); long i, j; i = 0; for (j = 0; j < r; j++) { if (i < k && j == I[i]) i++; else swap(W[j-i], W[j]); } } static void SumCoeffs(ZZ& sum, const ZZX& a) { ZZ res; res = 0; long i; long n = a.rep.length(); for (i = 0; i < n; i++) res += a.rep[i]; sum = res; } static void SumCoeffs(ZZ_p& sum, const ZZ_pX& a) { ZZ_p res; res = 0; long i; long n = a.rep.length(); for (i = 0; i < n; i++) res += a.rep[i]; sum = res; } static long ConstTermTest(const vec_ZZ_p& W, const vec_long& I, const ZZ& ct, const ZZ_p& lc, vec_ZZ_p& prod, long& ProdLen) { long k = I.length(); ZZ_p t; ZZ t1, t2; long i; if (ProdLen == 0) { mul(prod[0], lc, W[I[0]]); ProdLen++; } for (i = ProdLen; i < k; i++) mul(prod[i], prod[i-1], W[I[i]]); ProdLen = k-1; // should make this a routine in ZZ_p t1 = rep(prod[k-1]); RightShift(t2, ZZ_p::modulus(), 1); if (t1 > t2) sub(t1, t1, ZZ_p::modulus()); return divide(ct, t1); } NTL_CHEAP_THREAD_LOCAL long ZZXFac_MaxPrune = 10; static long pruning_bnd(long r, long k) { double x = 0; long i; for (i = 0; i < k; i++) { x += log(double(r-i)/double(k-i)); } return long((x/log(2.0)) * 0.75); } static long shamt_tab_init(long pos, long card, long pruning, long thresh1_len) { double x = 1; long i; for (i = 0; i < card; i++) { x *= double(pos-i)/double(card-i); } x *= pruning; // this can be adjusted to control the density if (pos <= 6) x *= 2; // a little boost that costs very little long t = long(ceil(log(x)/log(2.0))); t = max(t, TBL_SHAMT); t = min(t, NTL_BITS_PER_LONG-thresh1_len); return NTL_BITS_PER_LONG-t; } // The following routine should only be called for k > 1, // and is only worth calling for k > 2. static void CardinalitySearch1(vec_ZZX& factors, ZZX& f, vec_ZZ_pX& W, LocalInfoT& LocalInfo, long k, long bnd, long verbose) { double start_time, end_time; if (verbose) { start_time = GetTime(); cerr << "\n************ "; cerr << "start cardinality " << k << "\n"; } if (k <= 1) LogicError("internal error: call CardinalitySearch"); // This test is needed to ensure correcntes of "n-2" test if (NumBits(k) > NTL_BITS_PER_LONG/2-2) ResourceError("Cardinality Search: k too large..."); vec_ZZ pdeg; CalcPossibleDegrees(pdeg, W, k); ZZ pd; bit_and(pd, pdeg[0], LocalInfo.PossibleDegrees); if (pd == 0) { if (verbose) cerr << "skipping\n"; return; } vec_long I, D; I.SetLength(k); D.SetLength(k); long r = W.length(); long initial_r = r; vec_ulong ratio, ratio_sum; ratio.SetLength(r); ratio_sum.SetLength(k); unsigned long epsilon = (1UL << (NTL_BITS_PER_LONG-ZZX_OVERLIFT)); unsigned long delta = (unsigned long) k; unsigned long thresh = epsilon + delta; unsigned long thresh1 = (epsilon << 1) + delta; long thresh1_len = NumBits(long(thresh1)); long pruning; pruning = min(r/2, ZZXFac_MaxPrune); pruning = min(pruning, pruning_bnd(r, k)); pruning = min(pruning, NTL_BITS_PER_LONG-EXTRA_BITS-thresh1_len); if (pruning <= 4) pruning = 0; long init_pruning = pruning; lookup_tab_t lookup_tab; shamt_tab_t shamt_tab; if (pruning) { long i, j; shamt_tab.SetLength(pruning+1); for (i = 2; i <= pruning; i++) { long len = min(k-1, i); shamt_tab[i].SetLength(len+1); shamt_tab[i][0] = shamt_tab[i][1] = 0; for (j = 2; j <= len; j++) shamt_tab[i][j] = shamt_tab_init(i, j, pruning, thresh1_len); } lookup_tab.SetLength(pruning+1); for (i = 2; i <= pruning; i++) { long len = min(k-1, i); lookup_tab[i].SetLength(len+1); for (j = 2; j <= len; j++) { lookup_tab[i][j].SetLength(((1L << (NTL_BITS_PER_LONG-shamt_tab[i][j]))+TBL_MSK) >> TBL_SHAMT); } } } if (verbose) { cerr << "pruning = " << pruning << "\n"; } vec_ZZ_p prod; prod.SetLength(k); long ProdLen; vec_ZZ_p prod1; prod1.SetLength(k); long ProdLen1; vec_ulong sum_stack; sum_stack.SetLength(k+1); long SumLen; vec_long upd; long i, state; long cnt = 0; ZZ ct; mul(ct, ConstTerm(f), LeadCoeff(f)); ZZ_p lc; conv(lc, LeadCoeff(f)); vec_vec_ulong pair_ratio; pair_ratio.SetLength(r); for (i = 0; i < r; i++) pair_ratio[i].SetLength(r); RatioInit1(ratio, W, lc, pruning, lookup_tab, pair_ratio, k, thresh1, shamt_tab); ZZ c1; SumCoeffs(c1, f); mul(c1, c1, LeadCoeff(f)); vec_ZZ_p sum_coeffs; sum_coeffs.SetLength(r); for (i = 0; i < r; i++) SumCoeffs(sum_coeffs[i], W[i]); vec_long degv; degv.SetLength(r); for (i = 0; i < r; i++) degv[i] = deg(W[i]); ZZ_pX gg; ZZX g, h; I[0] = 0; long loop_cnt = 0, degree_cnt = 0, n2_cnt = 0, sl_cnt = 0, ct_cnt = 0, pl_cnt = 0, c1_cnt = 0, pl1_cnt = 0, td_cnt = 0; ZZ loop_total, degree_total, n2_total, sl_total, ct_total, pl_total, c1_total, pl1_total, td_total; while (I[0] <= r-k) { bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); D[0] = degv[I[0]]; ratio_sum[0] = ratio[I[0]] + thresh; i = 1; state = 0; ProdLen = 0; ProdLen1 = 0; SumLen = 0; for (;;) { cnt++; if (cnt > 2000000) { if (verbose) { loop_total += loop_cnt; loop_cnt = 0; degree_total += degree_cnt; degree_cnt = 0; n2_total += n2_cnt; n2_cnt = 0; sl_total += sl_cnt; sl_cnt = 0; ct_total += ct_cnt; ct_cnt = 0; pl_total += pl_cnt; pl_cnt = 0; c1_total += c1_cnt; c1_cnt = 0; pl1_total += pl1_cnt; pl1_cnt = 0; td_total += td_cnt; td_cnt = 0; } cnt = 0; UpdateLocalInfo(LocalInfo, pdeg, W, factors, f, k, verbose); bit_and(pd, pdeg[I[0]], LocalInfo.PossibleDegrees); if (IsZero(pd)) { if (verbose) cerr << "skipping\n"; goto done; } unpack(upd, pd, LocalInfo.n); } if (i == k-1) { unsigned long ratio_sum_last = ratio_sum[k-2]; long I_last = I[k-2]; { long D_last = D[k-2]; unsigned long rs; long I_this; long D_this; for (I_this = I_last+1; I_this < r; I_this++) { loop_cnt++; rs = ratio_sum_last + ratio[I_this]; if (rs > thresh1) { cnt++; continue; } degree_cnt++; D_this = D_last + degv[I_this]; if (!upd[D_this]) { cnt++; continue; } n2_cnt++; sl_cnt += (k-SumLen); I[k-1] = I_this; if (!SecondOrderTest(I, pair_ratio, sum_stack, SumLen)) { cnt += 2; continue; } c1_cnt++; pl1_cnt += (k-ProdLen1); if (!ConstTermTest(sum_coeffs, I, c1, lc, prod1, ProdLen1)) { cnt += 100; continue; } ct_cnt++; pl_cnt += (k-ProdLen); D[k-1] = D_this; if (!ConstTermTest(W, I, ct, lc, prod, ProdLen)) { cnt += 100; continue; } td_cnt++; if (verbose) { cerr << "+"; } cnt += 1000; if (2*D[k-1] <= deg(f)) { mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { continue; } // factor found! append(factors, g); if (verbose) { cerr << "degree " << deg(g) << " factor found\n"; } f = h; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } else { InvMul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if(MaxBits(g) > bnd) { continue; } if (verbose) { cerr << "*"; } PrimitivePart(g, g); if (!divide(h, f, g)) { continue; } // factor found! append(factors, h); if (verbose) { cerr << "degree " << deg(h) << " factor found\n"; } f = g; mul(ct, ConstTerm(f), LeadCoeff(f)); conv(lc, LeadCoeff(f)); } RemoveFactors(W, I); RemoveFactors1(degv, I, r); RemoveFactors1(sum_coeffs, I, r); RemoveFactors1(ratio, I, r); RemoveFactors1(pair_ratio, I, r); r = W.length(); cnt = 0; pruning = min(pruning, r/2); if (pruning <= 4) pruning = 0; InitTab(lookup_tab, ratio, r, k, thresh1, shamt_tab, pruning); if (2*k > r) goto done; else goto restart; } /* end of inner for loop */ } i--; state = 1; } else { if (state == 0) { long I_i = I[i-1] + 1; I[i] = I_i; long pruned; if (pruning && r-I_i <= pruning) { long pos = r-I_i; unsigned long rs = ratio_sum[i-1]; unsigned long index1 = (rs >> shamt_tab[pos][k-i]); if (lookup_tab[pos][k-i][index1 >> TBL_SHAMT] & (1UL << (index1&TBL_MSK))) pruned = 0; else pruned = 1; } else pruned = 0; if (pruned) { i--; state = 1; } else { D[i] = D[i-1] + degv[I_i]; ratio_sum[i] = ratio_sum[i-1] + ratio[I_i]; i++; } } else { // state == 1 loop_cnt++; if (i < ProdLen) ProdLen = i; if (i < ProdLen1) ProdLen1 = i; if (i < SumLen) SumLen = i; long I_i = (++I[i]); if (i == 0) break; if (I_i > r-k+i) { i--; } else { long pruned; if (pruning && r-I_i <= pruning) { long pos = r-I_i; unsigned long rs = ratio_sum[i-1]; unsigned long index1 = (rs >> shamt_tab[pos][k-i]); if (lookup_tab[pos][k-i][index1 >> TBL_SHAMT] & (1UL << (index1&TBL_MSK))) pruned = 0; else pruned = 1; } else pruned = 0; if (pruned) { i--; } else { D[i] = D[i-1] + degv[I_i]; ratio_sum[i] = ratio_sum[i-1] + ratio[I_i]; i++; state = 0; } } } } } restart: ; } done: if (verbose) { end_time = GetTime(); cerr << "\n************ "; cerr << "end cardinality " << k << "\n"; cerr << "time: " << (end_time-start_time) << "\n"; ZZ loops_max = choose_fn(initial_r+1, k); ZZ tuples_max = choose_fn(initial_r, k); loop_total += loop_cnt; degree_total += degree_cnt; n2_total += n2_cnt; sl_total += sl_cnt; ct_total += ct_cnt; pl_total += pl_cnt; c1_total += c1_cnt; pl1_total += pl1_cnt; td_total += td_cnt; cerr << "\n"; PrintInfo("loops: ", loop_total, loops_max); PrintInfo("degree tests: ", degree_total, tuples_max); PrintInfo("n-2 tests: ", n2_total, tuples_max); cerr << "ave sum len: "; if (n2_total == 0) cerr << "--"; else cerr << (to_double(sl_total)/to_double(n2_total)); cerr << "\n"; PrintInfo("f(1) tests: ", c1_total, tuples_max); cerr << "ave prod len: "; if (c1_total == 0) cerr << "--"; else cerr << (to_double(pl1_total)/to_double(c1_total)); cerr << "\n"; PrintInfo("f(0) tests: ", ct_total, tuples_max); cerr << "ave prod len: "; if (ct_total == 0) cerr << "--"; else cerr << (to_double(pl_total)/to_double(ct_total)); cerr << "\n"; PrintInfo("trial divs: ", td_total, tuples_max); } } static void FindTrueFactors(vec_ZZX& factors, const ZZX& ff, const vec_ZZX& w, const ZZ& P, LocalInfoT& LocalInfo, long verbose, long bnd) { ZZ_pBak bak; bak.save(); ZZ_p::init(P); long r = w.length(); vec_ZZ_pX W; W.SetLength(r); long i; for (i = 0; i < r; i++) conv(W[i], w[i]); ZZX f; f = ff; long k; k = 1; factors.SetLength(0); while (2*k <= W.length()) { if (k <= 1) CardinalitySearch(factors, f, W, LocalInfo, k, bnd, verbose); else CardinalitySearch1(factors, f, W, LocalInfo, k, bnd, verbose); k++; } append(factors, f); bak.restore(); } /**********************************************************************\ van Hoeij's algorithm \**********************************************************************/ const long van_hoeij_size_thresh = 12; // Use van Hoeij's algorithm if number of modular factors exceeds this bound. // Must be >= 1. const long van_hoeij_card_thresh = 3; // Switch to knapsack method if cardinality of candidate factors // exceeds this bound. // Must be >= 1. // This routine assumes that the input f is a non-zero polynomial // of degree n, and returns the value f(a). static ZZ PolyEval(const ZZX& f, const ZZ& a) { if (f == 0) LogicError("PolyEval: internal error"); long n = deg(f); ZZ acc, t1, t2; long i; acc = f.rep[n]; for (i = n-1; i >= 0; i--) { mul(t1, acc, a); add(acc, t1, f.rep[i]); } return acc; } // This routine assumes that the input f is a polynomial with non-zero constant // term, of degree n, and with leading coefficient c; it returns // an upper bound on the absolute value of the roots of the // monic, integer polynomial g(X) = c^{n-1} f(X/c). static ZZ RootBound(const ZZX& f) { if (ConstTerm(f) == 0) LogicError("RootBound: internal error"); long n = deg(f); ZZX g; long i; g = f; if (g.rep[n] < 0) negate(g.rep[n], g.rep[n]); for (i = 0; i < n; i++) { if (g.rep[i] > 0) negate(g.rep[i], g.rep[i]); } ZZ lb, ub, mb; lb = 0; ub = 1; while (PolyEval(g, ub) < 0) { ub = 2*ub; } // lb < root <= ub while (ub - lb > 1) { ZZ mb = (ub + lb)/2; if (PolyEval(g, mb) < 0) lb = mb; else ub = mb; } return ub*g.rep[n]; } // This routine takes as input an n x m integer matrix M, where the rows of M // are assumed to be linearly independent. // It is also required that both n and m are non-zero. // It computes an integer d, along with an n x m matrix R, such that // R*d^{-1} is the reduced row echelon form of M. // The routine is probabilistic: the output is always correct, but the // routine may abort the program with negligible probability // (specifically, if GenPrime returns a composite, and the modular // gauss routine can't invert a non-zero element). static void gauss(ZZ& d_out, mat_ZZ& R_out, const mat_ZZ& M) { long n = M.NumRows(); long m = M.NumCols(); if (n == 0 || m == 0) LogicError("gauss: internal error"); zz_pBak bak; bak.save(); for (;;) { long p = GenPrime_long(NTL_SP_NBITS); zz_p::init(p); mat_zz_p MM; conv(MM, M); long r = gauss(MM); if (r < n) continue; // compute pos(1..n), so that pos(i) is the index // of the i-th pivot column vec_long pos; pos.SetLength(n); long i, j; for (i = j = 1; i <= n; i++) { while (MM(i, j) == 0) j++; pos(i) = j; j++; } // compute the n x n sub-matrix consisting of the // pivot columns of M mat_ZZ S; S.SetDims(n, n); for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) S(i, j) = M(i, pos(j)); mat_ZZ S_inv; ZZ d; inv(d, S_inv, S); if (d == 0) continue; mat_ZZ R; mul(R, S_inv, M); // now check that R is of the right form, which it will be // if we were not unlucky long OK = 1; for (i = 1; i <= n && OK; i++) { for (j = 1; j < pos(i) && OK; j++) if (R(i, j) != 0) OK = 0; if (R(i, pos(i)) != d) OK = 0; for (j = 1; j < i && OK; j++) if (R(j, pos(i)) != 0) OK = 0; } if (!OK) continue; d_out = d; R_out = R; break; } } // The input polynomial f should be monic, and deg(f) > 0. // The input P should be > 1. // Tr.length() >= d, and Tr(i), for i = 1..d-1, should be the // Tr_i(f) mod P (in van Hoeij's notation). // The quantity Tr_d(f) mod P is computed, and stored in Tr(d). void ComputeTrace(vec_ZZ& Tr, const ZZX& f, long d, const ZZ& P) { long n = deg(f); // check arguments if (n <= 0 || LeadCoeff(f) != 1) LogicError("ComputeTrace: internal error (1)"); if (d <= 0) LogicError("ComputeTrace: internal error (2)"); if (Tr.length() < d) LogicError("ComputeTrace: internal error (3)"); if (P <= 1) LogicError("ComputeTrace: internal error (4)"); // treat d > deg(f) separately if (d > n) { ZZ t1, t2; long i; t1 = 0; for (i = 1; i <= n; i++) { mul(t2, Tr(i + d - n - 1), f.rep[i-1]); add(t1, t1, t2); } rem(t1, t1, P); NegateMod(t1, t1, P); Tr(d) = t1; } else { ZZ t1, t2; long i; mul(t1, f.rep[n-d], d); for (i = 1; i < d; i++) { mul(t2, Tr(i), f.rep[n-d+i]); add(t1, t1, t2); } rem(t1, t1, P); NegateMod(t1, t1, P); Tr(d) = t1; } } // Tr(1..d) are traces as computed above. // C and pb have length at least d. // For i = 1..d, pb(i) = p^{a_i} for a_i > 0. // pdelta = p^delta for delta > 0. // P = p^a for some a >= max{ a_i : i=1..d }. // This routine computes C(1..d), where // C(i) = C_{a_i}^{a_i + delta}( Tr(i)*lc^i ) for i = 1..d. void ChopTraces(vec_ZZ& C, const vec_ZZ& Tr, long d, const vec_ZZ& pb, const ZZ& pdelta, const ZZ& P, const ZZ& lc) { if (d <= 0) LogicError("ChopTraces: internal error (1)"); if (C.length() < d) LogicError("ChopTraces: internal error (2)"); if (Tr.length() < d) LogicError("ChopTraces: internal error (3)"); if (pb.length() < d) LogicError("ChopTraces: internal error (4)"); if (P <= 1) LogicError("ChopTraces: internal error (5)"); ZZ lcpow, lcred; lcpow = 1; rem(lcred, lc, P); ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); ZZ t1, t2; long i; for (i = 1; i <= d; i++) { MulMod(lcpow, lcpow, lcred, P); MulMod(t1, lcpow, Tr(i), P); RightShift(t2, pb(i), 1); add(t1, t1, t2); div(t1, t1, pb(i)); rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); C(i) = t1; } } // Similar to above, but computes a linear combination of traces. static void DenseChopTraces(vec_ZZ& C, const vec_ZZ& Tr, long d, long d1, const ZZ& pb_eff, const ZZ& pdelta, const ZZ& P, const ZZ& lc, const mat_ZZ& A) { ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); ZZ pb_eff_2; RightShift(pb_eff_2, pb_eff, 1); ZZ acc, t1, t2; long i, j; ZZ lcpow, lcred; rem(lcred, lc, P); for (i = 1; i <= d1; i++) { lcpow = 1; acc = 0; for (j = 1; j <= d; j++) { MulMod(lcpow, lcpow, lcred, P); MulMod(t1, lcpow, Tr(j), P); rem(t2, A(i, j), P); MulMod(t1, t1, t2, P); AddMod(acc, acc, t1, P); } t1 = acc; add(t1, t1, pb_eff_2); div(t1, t1, pb_eff); rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); C(i) = t1; } } static void Compute_pb(vec_long& b,vec_ZZ& pb, long p, long d, const ZZ& root_bound, long n) { ZZ t1, t2; long i; t1 = 2*power(root_bound, d)*n; if (d == 1) { i = 0; t2 = 1; } else { i = b(d-1); t2 = pb(d-1); } while (t2 <= t1) { i++; t2 *= p; } b.SetLength(d); b(d) = i; pb.SetLength(d); pb(d) = t2; } static void Compute_pdelta(long& delta, ZZ& pdelta, long p, long bit_delta) { ZZ t1; long i; i = delta; t1 = pdelta; while (NumBits(t1) <= bit_delta) { i++; t1 *= p; } delta = i; pdelta = t1; } static void BuildReductionMatrix(mat_ZZ& M, long& C, long r, long d, const ZZ& pdelta, const vec_vec_ZZ& chop_vec, const mat_ZZ& B_L, long verbose) { long s = B_L.NumRows(); C = long( sqrt(double(d) * double(r)) / 2.0 ) + 1; M.SetDims(s+d, r+d); clear(M); long i, j, k; ZZ t1, t2; for (i = 1; i <= s; i++) for (j = 1; j <= r; j++) mul(M(i, j), B_L(i, j), C); ZZ pdelta_2; RightShift(pdelta_2, pdelta, 1); long maxbits = 0; for (i = 1; i <= s; i++) for (j = 1; j <= d; j++) { t1 = 0; for (k = 1; k <= r; k++) { mul(t2, B_L(i, k), chop_vec(k)(j)); add(t1, t1, t2); } rem(t1, t1, pdelta); if (t1 > pdelta_2) sub(t1, t1, pdelta); maxbits = max(maxbits, NumBits(t1)); M(i, j+r) = t1; } for (i = 1; i <= d; i++) M(i+s, i+r) = pdelta; if (verbose) cerr << "ratio = " << double(maxbits)/double(NumBits(pdelta)) << "; "; } static void CutAway(mat_ZZ& B1, vec_ZZ& D, mat_ZZ& M, long C, long r, long d) { long k = M.NumRows(); ZZ bnd = 4*to_ZZ(C)*to_ZZ(C)*to_ZZ(r) + to_ZZ(d)*to_ZZ(r)*to_ZZ(r); while (k >= 1 && 4*D[k] > bnd*D[k-1]) k--; mat_ZZ B2; B2.SetDims(k, r); long i, j; for (i = 1; i <= k; i++) for (j = 1; j <= r; j++) div(B2(i, j), M(i, j), C); M.kill(); // save space D.kill(); ZZ det2; long rnk; rnk = image(det2, B2); B1.SetDims(rnk, r); for (i = 1; i <= rnk; i++) for (j = 1; j <= r; j++) B1(i, j) = B2(i + k - rnk, j); } static long GotThem(vec_ZZX& factors, const mat_ZZ& B_L, const vec_ZZ_pX& W, const ZZX& f, long bnd, long verbose) { double tt0, tt1; ZZ det; mat_ZZ R; long s, r; long i, j, cnt; if (verbose) { cerr << " checking A (s = " << B_L.NumRows() << "): gauss..."; } tt0 = GetTime(); gauss(det, R, B_L); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "; "; // check if condition A holds s = B_L.NumRows(); r = B_L.NumCols(); for (j = 0; j < r; j++) { cnt = 0; for (i = 0; i < s; i++) { if (R[i][j] == 0) continue; if (R[i][j] != det) { if (verbose) cerr << "failed.\n"; return 0; } cnt++; } if (cnt != 1) { if (verbose) cerr << "failed.\n"; return 0; } } if (verbose) { cerr << "passed.\n"; cerr << " checking B..."; } // extract relevant information from R vec_vec_long I_vec; I_vec.SetLength(s); vec_long deg_vec; deg_vec.SetLength(s); for (i = 0; i < s; i++) { long dg = 0; for (j = 0; j < r; j++) { if (R[i][j] != 0) append(I_vec[i], j); dg += deg(W[j]); } deg_vec[i] = dg; } R.kill(); // save space // check if any candidate factor is the product of too few // modular factors for (i = 0; i < s; i++) if (I_vec[i].length() <= van_hoeij_card_thresh) { if (verbose) cerr << "X\n"; return 0; } if (verbose) cerr << "1"; // sort deg_vec, I_vec in order of increasing degree for (i = 0; i < s-1; i++) for (j = 0; j < s-1-i; j++) if (deg_vec[j] > deg_vec[j+1]) { _ntl_swap(deg_vec[j], deg_vec[j+1]); swap(I_vec[j], I_vec[j+1]); } // perform constant term tests ZZ ct; mul(ct, LeadCoeff(f), ConstTerm(f)); ZZ half_P; RightShift(half_P, ZZ_p::modulus(), 1); ZZ_p lc, prod; conv(lc, LeadCoeff(f)); ZZ t1; for (i = 0; i < s; i++) { vec_long& I = I_vec[i]; prod = lc; for (j = 0; j < I.length(); j++) mul(prod, prod, ConstTerm(W[I[j]])); t1 = rep(prod); if (t1 > half_P) sub(t1, t1, ZZ_p::modulus()); if (!divide(ct, t1)) { if (verbose) cerr << "X\n"; return 0; } } if (verbose) cerr << "2"; // multiply out polynomials and perform size tests vec_ZZX fac; ZZ_pX gg; ZZX g; for (i = 0; i < s-1; i++) { vec_long& I = I_vec[i]; mul(gg, W, I); mul(gg, gg, lc); BalCopy(g, gg); if (MaxBits(g) > bnd) { if (verbose) cerr << "X\n"; return 0; } PrimitivePart(g, g); append(fac, g); } if (verbose) cerr << "3"; // finally...trial division ZZX f1 = f; ZZX h; for (i = 0; i < s-1; i++) { if (!divide(h, f1, fac[i])) { cerr << "X\n"; return 0; } f1 = h; } // got them! if (verbose) cerr << "$\n"; append(factors, fac); append(factors, f1); return 1; } void AdditionalLifting(ZZ& P1, long& e1, vec_ZZX& w1, long p, long new_bound, const ZZX& f, long doubling, long verbose) { long new_e1; if (doubling) new_e1 = max(2*e1, new_bound); // at least double e1 else new_e1 = new_bound; if (verbose) { cerr << ">>> additional hensel lifting to " << new_e1 << "...\n"; } ZZ new_P1; power(new_P1, p, new_e1); ZZX f1; ZZ t1, t2; long i; long n = deg(f); if (LeadCoeff(f) == 1) f1 = f; else if (LeadCoeff(f) == -1) negate(f1, f); else { rem(t1, LeadCoeff(f), new_P1); InvMod(t1, t1, new_P1); f1.rep.SetLength(n+1); for (i = 0; i <= n; i++) { mul(t2, f.rep[i], t1); rem(f1.rep[i], t2, new_P1); } } zz_pBak bak; bak.save(); zz_p::init(p, NextPowerOfTwo(n)+1); long r = w1.length(); vec_zz_pX ww1; ww1.SetLength(r); for (i = 0; i < r; i++) conv(ww1[i], w1[i]); w1.kill(); double tt0, tt1; tt0 = GetTime(); MultiLift(w1, ww1, f1, new_e1, verbose); tt1 = GetTime(); if (verbose) { cerr << "lifting time: " << (tt1-tt0) << "\n\n"; } P1 = new_P1; e1 = new_e1; bak.restore(); } static void Compute_pb_eff(long& b_eff, ZZ& pb_eff, long p, long d, const ZZ& root_bound, long n, long ran_bits) { ZZ t1, t2; long i; if (root_bound == 1) t1 = (to_ZZ(d)*to_ZZ(n)) << (ran_bits + 1); else t1 = (power(root_bound, d)*n) << (ran_bits + 2); i = 0; t2 = 1; while (t2 <= t1) { i++; t2 *= p; } b_eff = i; pb_eff = t2; } static long d1_val(long bit_delta, long r, long s) { return long( 0.30*double(r)*double(s)/double(bit_delta) ) + 1; } // Next comes van Hoeij's algorithm itself. // Some notation that differs from van Hoeij's paper: // n = deg(f) // r = # modular factors // s = dim(B_L) (gets smaller over time) // d = # traces used // d1 = number of "compressed" traces // // The algorithm starts with a "sparse" version of van Hoeij, so that // at first the traces d = 1, 2, ... are used in conjunction with // a d x d identity matrix for van Hoeij's matrix A. // The number of "excess" bits used for each trace, bit_delta, is initially // 2*r. // // When d*bit_delta exceeds 0.25*r*s, we switch to // a "dense" mode, where we use only about 0.25*r*s "compressed" traces. // These bounds follow from van Hoeij's heuristic estimates. // // In sparse mode, d and bit_delta increase exponentially (but gently). // In dense mode, but d increases somewhat more aggressively, // and bit_delta is increased more gently. static void FindTrueFactors_vH(vec_ZZX& factors, const ZZX& ff, const vec_ZZX& w, const ZZ& P, long p, long e, LocalInfoT& LocalInfo, long verbose, long bnd) { const long SkipSparse = 0; ZZ_pBak bak; bak.save(); ZZ_p::init(P); long r = w.length(); vec_ZZ_pX W; W.SetLength(r); long i, j; for (i = 0; i < r; i++) conv(W[i], w[i]); ZZX f; f = ff; long k; k = 1; factors.SetLength(0); while (2*k <= W.length() && (k <= van_hoeij_card_thresh || W.length() <= van_hoeij_size_thresh)) { if (k <= 1) CardinalitySearch(factors, f, W, LocalInfo, k, bnd, verbose); else CardinalitySearch1(factors, f, W, LocalInfo, k, bnd, verbose); k++; } if (2*k > W.length()) { // rest is irreducible, so we're done append(factors, f); } else { // now we apply van Hoeij's algorithm proper to f double time_start, time_stop, lll_time, tt0, tt1; time_start = GetTime(); lll_time = 0; if (verbose) { cerr << "\n\n*** starting knapsack procedure\n"; } ZZ P1 = P; long e1 = e; // invariant: P1 = p^{e1} r = W.length(); vec_ZZX w1; w1.SetLength(r); for (i = 0; i < r; i++) conv(w1[i], W[i]); long n = deg(f); mat_ZZ B_L; // van Hoeij's lattice ident(B_L, r); long d = 0; // number of traces long bit_delta = 0; // number of "excess" bits vec_long b; vec_ZZ pb; // pb(i) = p^{b(i)} long delta = 0; ZZ pdelta = to_ZZ(1); // pdelta = p^delta pdelta = 1; vec_vec_ZZ trace_vec; trace_vec.SetLength(r); vec_vec_ZZ chop_vec; chop_vec.SetLength(r); ZZ root_bound = RootBound(f); if (verbose) { cerr << "NumBits(root_bound) = " << NumBits(root_bound) << "\n"; } long dense = 0; long ran_bits = 32; long loop_cnt = 0; long s = r; for (;;) { loop_cnt++; // if we are using the power hack, then we do not try too hard... // this is really a hack on a hack! if (ok_to_abandon && ((d >= 2 && s > 128) || (d >= 3 && s > 32) || (d >= 4 && s > 8) || d >= 5) ) { if (verbose) cerr << " abandoning\n"; append(factors, f); break; } long d_last, d_inc, d_index; d_last = d; // set d_inc: if (!dense) { d_inc = 1 + d/8; } else { d_inc = 1 + d/4; } d_inc = min(d_inc, n-1-d); d += d_inc; // set bit_delta: if (bit_delta == 0) { // set initial value...don't make it any smaller than 2*r bit_delta = 2*r; } else { long extra_bits; if (!dense) { extra_bits = 1 + bit_delta/8; } else if (d_inc != 0) { if (d1_val(bit_delta, r, s) > 1) extra_bits = 1 + bit_delta/16; else extra_bits = 0; } else extra_bits = 1 + bit_delta/8; bit_delta += extra_bits; } if (d > d1_val(bit_delta, r, s)) dense = 1; Compute_pdelta(delta, pdelta, p, bit_delta); long d1; long b_eff; ZZ pb_eff; if (!dense) { for (d_index = d_last + 1; d_index <= d; d_index++) Compute_pb(b, pb, p, d_index, root_bound, n); d1 = d; b_eff = b(d); pb_eff = pb(d); } else { d1 = d1_val(bit_delta, r, s); Compute_pb_eff(b_eff, pb_eff, p, d, root_bound, n, ran_bits); } if (verbose) { cerr << "*** d = " << d << "; s = " << s << "; delta = " << delta << "; b_eff = " << b_eff; if (dense) cerr << "; dense [" << d1 << "]"; cerr << "\n"; } if (b_eff + delta > e1) { long doubling; doubling = 1; AdditionalLifting(P1, e1, w1, p, b_eff + delta, f, doubling, verbose); if (verbose) { cerr << ">>> recomputing traces..."; } tt0 = GetTime(); trace_vec.kill(); trace_vec.SetLength(r); for (i = 0; i < r; i++) { trace_vec[i].SetLength(d_last); for (d_index = 1; d_index <= d_last; d_index++) { ComputeTrace(trace_vec[i], w1[i], d_index, P1); } } tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; } if (verbose) cerr << " trace..."; tt0 = GetTime(); mat_ZZ A; if (dense) { A.SetDims(d1, d); for (i = 1; i <= d1; i++) for (j = 1; j <= d; j++) { RandomBits(A(i, j), ran_bits); if (RandomBnd(2)) negate(A(i, j), A(i, j)); } } for (i = 0; i < r; i++) { trace_vec[i].SetLength(d); for (d_index = d_last + 1; d_index <= d; d_index++) ComputeTrace(trace_vec[i], w1[i], d_index, P1); chop_vec[i].SetLength(d1); if (!dense) ChopTraces(chop_vec[i], trace_vec[i], d, pb, pdelta, P1, LeadCoeff(f)); else DenseChopTraces(chop_vec[i], trace_vec[i], d, d1, pb_eff, pdelta, P1, LeadCoeff(f), A); } A.kill(); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; mat_ZZ M; long C; if (verbose) cerr << " building matrix..."; tt0 = GetTime(); BuildReductionMatrix(M, C, r, d1, pdelta, chop_vec, B_L, verbose); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; if (SkipSparse) { if (!dense) { if (verbose) cerr << "skipping LLL\n"; continue; } } if (verbose) cerr << " LLL..."; tt0 = GetTime(); vec_ZZ D; long rnk = LLL_plus(D, M); tt1 = GetTime(); lll_time += (tt1-tt0); if (verbose) cerr << (tt1-tt0) << "\n"; if (rnk != s + d1) { LogicError("van Hoeij -- bad rank"); } mat_ZZ B1; if (verbose) cerr << " CutAway..."; tt0 = GetTime(); CutAway(B1, D, M, C, r, d1); tt1 = GetTime(); if (verbose) cerr << (tt1-tt0) << "\n"; if (B1.NumRows() >= s) continue; // no progress...try again // otherwise, update B_L and test if we are done swap(B1, B_L); B1.kill(); s = B_L.NumRows(); if (s == 0) LogicError("oops! s == 0 should not happen!"); if (s == 1) { if (verbose) cerr << " irreducible!\n"; append(factors, f); break; } if (s > r / (van_hoeij_card_thresh + 1)) continue; // dimension too high...we can't be done if (GotThem(factors, B_L, W, f, bnd, verbose)) break; } time_stop = GetTime(); if (verbose) { cerr << "*** knapsack finished: total time = " << (time_stop - time_start) << "; LLL time = " << lll_time << "\n"; } } bak.restore(); } static void ll_SFFactor(vec_ZZX& factors, const ZZX& ff, long verbose, long bnd) // input is primitive and square-free, with positive leading // coefficient { if (deg(ff) <= 1) { factors.SetLength(1); factors[0] = ff; if (verbose) { cerr << "*** SFFactor, trivial case 1.\n"; } return; } // remove a factor of X, if necessary ZZX f; long xfac; long rev; double t; if (IsZero(ConstTerm(ff))) { RightShift(f, ff, 1); xfac = 1; } else { f = ff; xfac = 0; } // return a factor of X-1 if necessary long x1fac = 0; ZZ c1; SumCoeffs(c1, f); if (c1 == 0) { x1fac = 1; div(f, f, ZZX(1,1) - 1); } SumCoeffs(c1, f); if (deg(f) <= 1) { long r = 0; factors.SetLength(0); if (deg(f) > 0) { factors.SetLength(r+1); factors[r] = f; r++; } if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1) - 1; r++; } if (verbose) { cerr << "*** SFFactor: trivial case 2.\n"; } return; } if (verbose) { cerr << "*** start SFFactor.\n"; } // reverse f if this makes lead coefficient smaller ZZ t1, t2; abs(t1, LeadCoeff(f)); abs(t2, ConstTerm(f)); if (t1 > t2) { inplace_rev(f); rev = 1; } else rev = 0; // obtain factorization modulo small primes if (verbose) { cerr << "factorization modulo small primes...\n"; t = GetTime(); } LocalInfoT LocalInfo; zz_pBak bak; bak.save(); UniquePtr spfactors( SmallPrimeFactorization(LocalInfo, f, verbose) ); if (!spfactors) { // f was found to be irreducible bak.restore(); if (verbose) { t = GetTime()-t; cerr << "small prime time: " << t << ", irreducible.\n"; } if (rev) inplace_rev(f); long r = 0; factors.SetLength(r+1); factors[r] = f; r++; if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1) - 1; r++; } return; } if (verbose) { t = GetTime()-t; cerr << "small prime time: "; cerr << t << ", number of factors = " << spfactors->length() << "\n"; } // prepare for Hensel lifting // first, calculate bit bound long bnd1; long n = deg(f); long i; long e; ZZ P; long p; bnd1 = MaxBits(f) + (NumBits(n+1)+1)/2; if (!bnd || bnd1 < bnd) bnd = bnd1; i = n/2; while (!bit(LocalInfo.PossibleDegrees, i)) i--; long lc_bnd = NumBits(LeadCoeff(f)); long coeff_bnd = bnd + lc_bnd + i; long lift_bnd; lift_bnd = coeff_bnd + 15; // +15 helps avoid trial divisions...can be any number >= 0 lift_bnd = max(lift_bnd, bnd + lc_bnd + 2*NumBits(n) + ZZX_OVERLIFT); // facilitates "n-1" and "n-2" tests lift_bnd = max(lift_bnd, lc_bnd + NumBits(c1)); // facilitates f(1) test lift_bnd += 2; // +2 needed to get inequalities right p = zz_p::modulus(); e = long(double(lift_bnd)/(log(double(p))/log(double(2)))); power(P, p, e); while (NumBits(P) <= lift_bnd) { mul(P, P, p); e++; } if (verbose) { cerr << "lifting bound = " << lift_bnd << " bits.\n"; cerr << "Hensel lifting to exponent " << e << "...\n"; t = GetTime(); } // third, compute f1 so that it is monic and equal to f mod P ZZX f1; if (LeadCoeff(f) == 1) f1 = f; else if (LeadCoeff(f) == -1) negate(f1, f); else { rem(t1, LeadCoeff(f), P); if (sign(P) < 0) LogicError("whoops!!!"); InvMod(t1, t1, P); f1.rep.SetLength(n+1); for (i = 0; i <= n; i++) { mul(t2, f.rep[i], t1); rem(f1.rep[i], t2, P); } } // Do Hensel lift vec_ZZX w; MultiLift(w, *spfactors, f1, e, verbose); if (verbose) { t = GetTime()-t; cerr << "\nlifting time: "; cerr << t << "\n\n"; } // We're done with zz_p...restore spfactors.reset(); bak.restore(); // search for true factors if (verbose) { cerr << "searching for true factors...\n"; t = GetTime(); } if (ZZXFac_van_Hoeij && w.length() > van_hoeij_size_thresh) FindTrueFactors_vH(factors, f, w, P, p, e, LocalInfo, verbose, coeff_bnd); else FindTrueFactors(factors, f, w, P, LocalInfo, verbose, coeff_bnd); if (verbose) { t = GetTime()-t; cerr << "factor search time " << t << "\n"; } long r = factors.length(); if (rev) { for (i = 0; i < r; i++) { inplace_rev(factors[i]); if (sign(LeadCoeff(factors[i])) < 0) negate(factors[i], factors[i]); } } if (xfac) { factors.SetLength(r+1); SetX(factors[r]); r++; } if (x1fac) { factors.SetLength(r+1); factors[r] = ZZX(1,1)-1; r++; } // that's it!! if (verbose) { cerr << "*** end SFFactor. degree sequence:\n"; for (i = 0; i < r; i++) cerr << deg(factors[i]) << " "; cerr << "\n"; } } static long DeflationFactor(const ZZX& f) { long n = deg(f); long m = 0; long i; for (i = 1; i <= n && m != 1; i++) { if (f.rep[i] != 0) m = GCD(m, i); } return m; } static void inflate(ZZX& g, const ZZX& f, long m) // input may not alias output { long n = deg(f); long i; g = 0; for (i = n; i >= 0; i--) SetCoeff(g, i*m, f.rep[i]); } static void deflate(ZZX& g, const ZZX& f, long m) // input may not alias output { long n = deg(f); long i; g = 0; for (i = n; i >= 0; i -= m) SetCoeff(g, i/m, f.rep[i]); } static void MakeFacList(vec_long& v, long m) { if (m <= 0) LogicError("internal error: MakeFacList"); v.SetLength(0); long p = 2; while (m > 1) { while (m % p == 0) { append(v, p); m = m / p; } p++; } } NTL_CHEAP_THREAD_LOCAL long ZZXFac_PowerHack = 1; void SFFactor(vec_ZZX& factors, const ZZX& ff, long verbose, long bnd) // input is primitive and square-free, with positive leading // coefficient { if (ff == 0) LogicError("SFFactor: bad args"); if (deg(ff) <= 0) { factors.SetLength(0); return; } if (!ZZXFac_PowerHack) { ok_to_abandon = 0; ll_SFFactor(factors, ff, verbose, bnd); return; } long m = DeflationFactor(ff); if (m == 1) { if (verbose) { cerr << "SFFactor -- no deflation\n"; } ok_to_abandon = 0; ll_SFFactor(factors, ff, verbose, bnd); return; } vec_long v; MakeFacList(v, m); long l = v.length(); if (verbose) { cerr << "SFFactor -- deflation: " << v << "\n"; } vec_ZZX res; res.SetLength(1); deflate(res[0], ff, m); long done; long j, k; done = 0; k = l-1; while (!done) { vec_ZZX res1; res1.SetLength(0); for (j = 0; j < res.length(); j++) { vec_ZZX res2; double t; if (verbose) { cerr << "begin - step " << k << ", " << j << "; deg = " << deg(res[j]) << "\n"; t = GetTime(); } if (k < 0) ok_to_abandon = 0; else ok_to_abandon = 1; ll_SFFactor(res2, res[j], verbose, k < 0 ? bnd : 0); if (verbose) { t = GetTime()-t; cerr << "end - step " << k << ", " << j << "; time = " << t << "\n\n"; } append(res1, res2); } if (k < 0) { done = 1; swap(res, res1); } else { vec_ZZX res2; res2.SetLength(res1.length()); for (j = 0; j < res1.length(); j++) inflate(res2[j], res1[j], v[k]); k--; swap(res, res2); } } factors = res; } void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose, long bnd) { ZZX ff = f; if (deg(ff) <= 0) { c = ConstTerm(ff); factors.SetLength(0); return; } content(c, ff); divide(ff, ff, c); long bnd1 = MaxBits(ff) + (NumBits(deg(ff)+1)+1)/2; if (!bnd || bnd > bnd1) bnd = bnd1; vec_pair_ZZX_long sfd; double t; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, ff); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); vec_ZZX x; long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; t = GetTime(); } SFFactor(x, sfd[i].a, verbose, bnd); if (verbose) { t = GetTime()-t; cerr << "total time for multiplicity " << sfd[i].b << ": " << t << "\n"; } for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } NTL_END_IMPL ntl-11.5.1/src/ZZ_p.cpp0000644417616742025610000001623714064716022016343 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL NTL_TLS_GLOBAL_DECL(SmartPtr, ZZ_pInfo_stg) NTL_TLS_GLOBAL_DECL(SmartPtr, ZZ_pTmpSpace_stg) NTL_CHEAP_THREAD_LOCAL ZZ_pInfoT *ZZ_pInfo = 0; NTL_CHEAP_THREAD_LOCAL ZZ_pTmpSpaceT *ZZ_pTmpSpace = 0; NTL_CHEAP_THREAD_LOCAL bool ZZ_pInstalled = false; ZZ_pInfoT::ZZ_pInfoT(const ZZ& NewP) { if (NewP <= 1) LogicError("ZZ_pContext: p must be > 1"); p = NewP; size = p.size(); ExtendedModulusSize = 2*size + (NTL_BITS_PER_LONG + NTL_ZZ_NBITS - 1)/NTL_ZZ_NBITS; } // we use a lazy strategy for initializing and installing // FFTInfo and TmpSpace related to a ZZ_p modulus. // The routines GetFFTInfo and GetTmpSpace make sure this process // is complete. void ZZ_p::DoInstall() { SmartPtr tmps; do { // NOTE: thread safe lazy init Lazy::Builder builder(ZZ_pInfo->FFTInfo); if (!builder()) break; UniquePtr FFTInfo; FFTInfo.make(); ZZ B, M, M1, M2, M3; long n, i; long q, t; mulmod_t qinv; sqr(B, ZZ_pInfo->p); LeftShift(B, B, NTL_FFTMaxRoot+NTL_FFTFudge); // FIXME: the following is quadratic time...would // be nice to get a faster solution... // One could estimate the # of primes by summing logs, // then multiply using a tree-based multiply, then // adjust up or down... // Assuming IEEE floating point, the worst case estimate // for error guarantees a correct answer +/- 1 for // numprimes up to 2^25...for sure we won't be // using that many primes...we can certainly put in // a sanity check, though. // If I want a more accuaruate summation (with using Kahan, // which has some portability issues), I could represent // numbers as x = a + f, where a is integer and f is the fractional // part. Summing in this representation introduces an *absolute* // error of 2 epsilon n, which is just as good as Kahan // for this application. // same strategy could also be used in the ZZX HomMul routine, // if we ever want to make that subquadratic set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = GetFFTPrime(n); n++; mul(M, M, q); } FFTInfo->NumPrimes = n; FFTInfo->MaxRoot = CalcMaxRoot(q); double fn = double(n); // NOTE: the following checks is somewhat academic, // but the implementation relies on it if (8.0*fn*(fn+48) > NTL_FDOUBLE_PRECISION) ResourceError("modulus too big"); FFTInfo->rem_struct.init(n, ZZ_pInfo->p, GetFFTPrime); FFTInfo->crt_struct.init(n, ZZ_pInfo->p, GetFFTPrime); if (!FFTInfo->crt_struct.special()) { FFTInfo->prime.SetLength(n); FFTInfo->prime_recip.SetLength(n); FFTInfo->u.SetLength(n); FFTInfo->uqinv.SetLength(n); // montgomery FFTInfo->reduce_struct.init(ZZ_pInfo->p, ZZ(n) << NTL_SP_NBITS); ZZ qq, rr; DivRem(qq, rr, M, ZZ_pInfo->p); NegateMod(FFTInfo->MinusMModP, rr, ZZ_pInfo->p); // montgomery FFTInfo->reduce_struct.adjust(FFTInfo->MinusMModP); for (i = 0; i < n; i++) { q = GetFFTPrime(i); qinv = GetFFTPrimeInv(i); long tt = rem(qq, q); mul(M2, ZZ_pInfo->p, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); // montgomery FFTInfo->reduce_struct.adjust(M2); FFTInfo->crt_struct.insert(i, M2); FFTInfo->prime[i] = q; FFTInfo->prime_recip[i] = 1/double(q); FFTInfo->u[i] = t; FFTInfo->uqinv[i] = PrepMulModPrecon(FFTInfo->u[i], q, qinv); } } tmps = MakeSmart(); tmps->crt_tmp_vec.fetch(FFTInfo->crt_struct); tmps->rem_tmp_vec.fetch(FFTInfo->rem_struct); builder.move(FFTInfo); } while (0); if (!tmps) { const ZZ_pFFTInfoT *FFTInfo = ZZ_pInfo->FFTInfo.get(); tmps = MakeSmart(); tmps->crt_tmp_vec.fetch(FFTInfo->crt_struct); tmps->rem_tmp_vec.fetch(FFTInfo->rem_struct); } NTL_TLS_GLOBAL_ACCESS(ZZ_pTmpSpace_stg); ZZ_pTmpSpace_stg = tmps; ZZ_pTmpSpace = ZZ_pTmpSpace_stg.get(); } void ZZ_p::init(const ZZ& p) { ZZ_pContext c(p); c.restore(); } void ZZ_pContext::save() { NTL_TLS_GLOBAL_ACCESS(ZZ_pInfo_stg); ptr = ZZ_pInfo_stg; } void ZZ_pContext::restore() const { if (ZZ_pInfo == ptr.get()) return; // NOTE: this simple optimization could be useful in some situations, // for example, a worker thread re-setting the current modulus // in a multi-threaded build NTL_TLS_GLOBAL_ACCESS(ZZ_pInfo_stg); ZZ_pInfo_stg = ptr; ZZ_pInfo = ZZ_pInfo_stg.get(); NTL_TLS_GLOBAL_ACCESS(ZZ_pTmpSpace_stg); ZZ_pTmpSpace_stg = 0; ZZ_pTmpSpace = 0; ZZ_pInstalled = false; } ZZ_pBak::~ZZ_pBak() { if (MustRestore) c.restore(); } void ZZ_pBak::save() { c.save(); MustRestore = true; } void ZZ_pBak::restore() { c.restore(); MustRestore = false; } const ZZ_p& ZZ_p::zero() { static const ZZ_p z(INIT_NO_ALLOC); // GLOBAL (assumes C++11 thread-safe init) return z; } NTL_CHEAP_THREAD_LOCAL ZZ_p::DivHandlerPtr ZZ_p::DivHandler = 0; ZZ_p::ZZ_p(INIT_VAL_TYPE, const ZZ& a) // NO_ALLOC { conv(*this, a); } ZZ_p::ZZ_p(INIT_VAL_TYPE, long a) // NO_ALLOC { conv(*this, a); } void conv(ZZ_p& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZRegister(y); conv(y, a); conv(x, y); } } istream& operator>>(istream& s, ZZ_p& x) { NTL_ZZRegister(y); NTL_INPUT_CHECK_RET(s, s >> y); conv(x, y); return s; } void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(x, a, T); } void inv(ZZ_p& x, const ZZ_p& a) { NTL_ZZRegister(T); if (InvModStatus(T, a._ZZ_p__rep, ZZ_p::modulus())) { if (!IsZero(a._ZZ_p__rep) && ZZ_p::DivHandler) (*ZZ_p::DivHandler)(a); InvModError("ZZ_p: division by non-invertible element", a._ZZ_p__rep, ZZ_p::modulus()); } x._ZZ_p__rep = T; } long operator==(const ZZ_p& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); NTL_ZZ_pRegister(T); conv(T, b); return a == T; } void add(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); add(x, a, T); } void sub(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); sub(x, a, T); } void sub(ZZ_p& x, long a, const ZZ_p& b) { NTL_ZZ_pRegister(T); conv(T, a); sub(x, T, b); } void mul(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); mul(x, a, T); } void div(ZZ_p& x, const ZZ_p& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); div(x, a, T); } void div(ZZ_p& x, long a, const ZZ_p& b) { if (a == 1) { inv(x, b); } else { NTL_ZZ_pRegister(T); conv(T, a); div(x, T, b); } } NTL_END_IMPL ntl-11.5.1/src/ZZ_pE.cpp0000644417616742025610000000405214064716022016440 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL NTL_TLS_GLOBAL_DECL(SmartPtr, ZZ_pEInfo_stg) NTL_CHEAP_THREAD_LOCAL ZZ_pEInfoT *ZZ_pEInfo = 0; ZZ_pEInfoT::ZZ_pEInfoT(const ZZ_pX& NewP) { build(p, NewP); _card_base = ZZ_p::modulus(); _card_exp = deg(NewP); } const ZZ& ZZ_pE::cardinality() { if (!ZZ_pEInfo) LogicError("ZZ_pE::cardinality: undefined modulus"); do { // NOTE: thread safe lazy init Lazy::Builder builder(ZZ_pEInfo->_card); if (!builder()) break; UniquePtr p; p.make(); power(*p, ZZ_pEInfo->_card_base, ZZ_pEInfo->_card_exp); builder.move(p); } while (0); return *ZZ_pEInfo->_card; } void ZZ_pE::init(const ZZ_pX& p) { ZZ_pEContext c(p); c.restore(); } void ZZ_pEContext::save() { NTL_TLS_GLOBAL_ACCESS(ZZ_pEInfo_stg); ptr = ZZ_pEInfo_stg; } void ZZ_pEContext::restore() const { NTL_TLS_GLOBAL_ACCESS(ZZ_pEInfo_stg); ZZ_pEInfo_stg = ptr; ZZ_pEInfo = ZZ_pEInfo_stg.get(); } ZZ_pEBak::~ZZ_pEBak() { if (MustRestore) c.restore(); } void ZZ_pEBak::save() { c.save(); MustRestore = true; } void ZZ_pEBak::restore() { c.restore(); MustRestore = false; } const ZZ_pE& ZZ_pE::zero() { static const ZZ_pE z(INIT_NO_ALLOC); // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, ZZ_pE& x) { ZZ_pX y; NTL_INPUT_CHECK_RET(s, s >> y); conv(x, y); return s; } void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void div(ZZ_pE& x, const ZZ_pE& a, long b) { NTL_ZZ_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { NTL_ZZ_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(ZZ_pE& x, long a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void div(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { ZZ_pE t; inv(t, b); mul(x, a, t); } void inv(ZZ_pE& x, const ZZ_pE& a) { InvMod(x._ZZ_pE__rep, a._ZZ_pE__rep, ZZ_pE::modulus()); } NTL_END_IMPL ntl-11.5.1/src/ZZ_pEX.cpp0000644417616742025610000017730614064716022016605 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL const ZZ_pEX& ZZ_pEX::zero() { static const ZZ_pEX z; // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, ZZ_pEX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZ_pEX& a) { return s << a.rep; } void ZZ_pEX::normalize() { long n; const ZZ_pE* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZ_pEX& a) { return a.rep.length() == 0; } long IsOne(const ZZ_pEX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const ZZ_pEX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_ZZ_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const ZZ_pEX& a, const ZZ_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } long operator==(const ZZ_pEX& a, const ZZ_pE& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { ZZ_pE aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& aa) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); NTL_ZZ_pRegister(a); // watch out for aliases! a = aa; m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pEX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZ_pRegister(T); T = a; SetCoeff(x, i, T); } } void SetCoeff(ZZ_pEX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZ_pEX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZ_pEX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ_pE& coeff(const ZZ_pEX& a, long i) { if (i < 0 || i > deg(a)) return ZZ_pE::zero(); else return a.rep[i]; } const ZZ_pE& LeadCoeff(const ZZ_pEX& a) { if (IsZero(a)) return ZZ_pE::zero(); else return a.rep[deg(a)]; } const ZZ_pE& ConstTerm(const ZZ_pEX& a) { if (IsZero(a)) return ZZ_pE::zero(); else return a.rep[0]; } void conv(ZZ_pEX& x, const ZZ_pE& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(ZZ_pEX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZ_pRegister(T); T = a; conv(x, T); } } void conv(ZZ_pEX& x, const ZZ& a) { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } void conv(ZZ_pEX& x, const ZZ_p& a) { if (IsZero(a)) clear(x); else if (IsOne(a)) set(x); else { x.rep.SetLength(1); conv(x.rep[0], a); x.normalize(); } } void conv(ZZ_pEX& x, const ZZ_pX& aa) { ZZ_pX a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(ZZ_pEX& x, const vec_ZZ_pE& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(ZZ_pEX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_pE *ap, *bp; ZZ_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pEX& x, const ZZ_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_pE *ap, *bp; ZZ_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); negate(x, x); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_pE& b, const ZZ_pEX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], x.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_pE *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void sub(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { NTL_ZZ_pRegister(T); // avoids aliasing problems T = a; negate(x, b); add(x, x, T); } void sub(ZZ_pEX& x, long a, const ZZ_pEX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void mul(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b) { if (&a == &b) { sqr(c, a); return; } if (IsZero(a) || IsZero(b)) { clear(c); return; } if (deg(a) == 0) { mul(c, b, ConstTerm(a)); return; } if (deg(b) == 0) { mul(c, a, ConstTerm(b)); return; } // general case...Kronecker subst ZZ_pX A, B, C; long da = deg(a); long db = deg(b); long n = ZZ_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(da+db+1, n2, 0)) ResourceError("overflow in ZZ_pEX mul"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const ZZ_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); B.rep.SetLength((db+1)*n2); for (i = 0; i <= db; i++) { const ZZ_pX& coeff = rep(b.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) B.rep[n2*i + j] = coeff.rep[j]; } B.normalize(); mul(C, A, B); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); ZZ_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pE& b) { if (IsZero(b)) { clear(x); return; } ZZ_pE t; t = b; long i, da; const ZZ_pE *ap; ZZ_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_p& b) { if (IsZero(b)) { clear(x); return; } NTL_ZZ_pRegister(t); t = b; long i, da; const ZZ_pE *ap; ZZ_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(ZZ_pEX& x, const ZZ_pEX& a, long b) { NTL_ZZ_pRegister(t); t = b; mul(x, a, t); } void sqr(ZZ_pEX& c, const ZZ_pEX& a) { if (IsZero(a)) { clear(c); return; } if (deg(a) == 0) { ZZ_pE res; sqr(res, ConstTerm(a)); conv(c, res); return; } // general case...Kronecker subst ZZ_pX A, C; long da = deg(a); long n = ZZ_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(2*da+1, n2, 0)) ResourceError("overflow in ZZ_pEX sqr"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const ZZ_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); sqr(C, A); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); ZZ_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n) { if (n < 0) LogicError("MulTrunc: bad args"); ZZ_pEX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (n < 0) LogicError("SqrTrunc: bad args"); ZZ_pEX t; sqr(t, a); trunc(x, t, n); } void CopyReverse(ZZ_pEX& x, const ZZ_pEX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_pE* ap = a.rep.elts(); ZZ_pE* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(ZZ_pEX& x, const ZZ_pEX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ_pE* xp; const ZZ_pE* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void random(ZZ_pEX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void negate(ZZ_pEX& x, const ZZ_pEX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ_pE* ap = a.rep.elts(); ZZ_pE* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } static void MulByXModAux(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEX& f) { long i, n, m; ZZ_pE* hh; const ZZ_pE *aa, *ff; ZZ_pE t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEX& f) { if (&h == &f) { ZZ_pEX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void PlainMul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const ZZ_pE *ap, *bp; ZZ_pE *xp; ZZ_pEX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; ZZ_pX t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void SetSize(vec_ZZ_pX& x, long n, long m) { x.SetLength(n); long i; for (i = 0; i < n; i++) x[i].rep.SetMaxLength(m); } void PlainDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da+1, 2*ZZ_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b, vec_ZZ_pX& x) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b, vec_ZZ_pX& x) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pE *qp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pEX: division by zero"); if (da < db) { clear(q); return; } ZZ_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da+1-db, 2*ZZ_pE::degree()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_pE *bp; ZZ_pX *xp; ZZ_pE LCInv, t; ZZ_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_ZZ_pX x; SetSize(x, da + 1, 2*ZZ_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void NewtonInv(ZZ_pEX& c, const ZZ_pEX& a, long e) { ZZ_pE x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); ZZ_pEX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(ZZ_pEX& c, const ZZ_pEX& a, long e) { if (e < 0) LogicError("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) ResourceError("overflow in InvTrunc"); NewtonInv(c, a, e); } const long ZZ_pEX_MOD_PLAIN = 0; const long ZZ_pEX_MOD_MUL = 1; void build(ZZ_pEXModulus& F, const ZZ_pEX& f) { long n = deg(f); if (n <= 0) LogicError("build(ZZ_pEXModulus,ZZ_pEX): deg(f) <= 0"); if (NTL_OVERFLOW(n, ZZ_pE::degree(), 0)) ResourceError("build(ZZ_pEXModulus,ZZ_pEX): overflow"); F.tracevec.make(); F.f = f; F.n = n; if (F.n < ZZ_pE::ModCross()) { F.method = ZZ_pEX_MOD_PLAIN; } else { F.method = ZZ_pEX_MOD_MUL; ZZ_pEX P1; ZZ_pEX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } ZZ_pEXModulus::ZZ_pEXModulus() { n = -1; method = ZZ_pEX_MOD_PLAIN; } ZZ_pEXModulus::~ZZ_pEXModulus() { } ZZ_pEXModulus::ZZ_pEXModulus(const ZZ_pEX& ff) { n = -1; method = ZZ_pEX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); } void UseMulDivRem21(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); q = P2; } void UseMulDiv21(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX P1; ZZ_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); ZZ_pEX qbuf(INIT_SIZE, n-1); ZZ_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } ZZ_pEX buf(INIT_SIZE, 2*n-1); ZZ_pEX qbuf(INIT_SIZE, n-1); ZZ_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) LogicError("MulMod: bad args"); ZZ_pEX t; mul(t, a, b); rem(c, t, F); } void SqrMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEXModulus& F) { if (deg(a) >= F.n) LogicError("MulMod: bad args"); ZZ_pEX t; sqr(t, a); rem(c, t, F); } void UseMulRem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; } void UseMulDivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; q = P2; } void UseMulDiv(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX P1; ZZ_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { ZZ_pEXModulus B; build(B, b); DivRem(q, r, a, B); } } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { ZZ_pEXModulus B; build(B, b); div(q, a, B); } } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pE T; inv(T, b); mul(q, a, T); } void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(q, a, T); } void div(ZZ_pEX& q, const ZZ_pEX& a, long b) { NTL_ZZ_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < ZZ_pE::DivCross() || sa-sb < ZZ_pE::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { ZZ_pEXModulus B; build(B, b); rem(r, a, B); } } void PlainGCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; ZZ_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_ZZ_pX tmp; SetSize(tmp, n, 2*ZZ_pE::degree()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } class _NTL_ZZ_pEXMatrix { private: _NTL_ZZ_pEXMatrix(const _NTL_ZZ_pEXMatrix&); // disable ZZ_pEX elts[2][2]; public: _NTL_ZZ_pEXMatrix() { } ~_NTL_ZZ_pEXMatrix() { } void operator=(const _NTL_ZZ_pEXMatrix&); ZZ_pEX& operator() (long i, long j) { return elts[i][j]; } const ZZ_pEX& operator() (long i, long j) const { return elts[i][j]; } }; void _NTL_ZZ_pEXMatrix::operator=(const _NTL_ZZ_pEXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } static void mul(ZZ_pEX& U, ZZ_pEX& V, const _NTL_ZZ_pEXMatrix& M) // (U, V)^T = M*(U, V)^T { ZZ_pEX t1, t2, t3; mul(t1, M(0,0), U); mul(t2, M(0,1), V); add(t3, t1, t2); mul(t1, M(1,0), U); mul(t2, M(1,1), V); add(V, t1, t2); U = t3; } static void mul(_NTL_ZZ_pEXMatrix& A, _NTL_ZZ_pEXMatrix& B, _NTL_ZZ_pEXMatrix& C) // A = B*C, B and C are destroyed { ZZ_pEX t1, t2; mul(t1, B(0,0), C(0,0)); mul(t2, B(0,1), C(1,0)); add(A(0,0), t1, t2); mul(t1, B(1,0), C(0,0)); mul(t2, B(1,1), C(1,0)); add(A(1,0), t1, t2); mul(t1, B(0,0), C(0,1)); mul(t2, B(0,1), C(1,1)); add(A(0,1), t1, t2); mul(t1, B(1,0), C(0,1)); mul(t2, B(1,1), C(1,1)); add(A(1,1), t1, t2); long i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { B(i,j).kill(); C(i,j).kill(); } } } void IterHalfGCD(_NTL_ZZ_pEXMatrix& M_out, ZZ_pEX& U, ZZ_pEX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; ZZ_pEX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } #define NTL_ZZ_pEX_HalfGCD_CROSSOVER (25) #define NTL_ZZ_pEX_GCD_CROSSOVER (275) void HalfGCD(_NTL_ZZ_pEXMatrix& M_out, const ZZ_pEX& U, const ZZ_pEX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; ZZ_pEX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_ZZ_pEX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_ZZ_pEXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } ZZ_pEX Q; _NTL_ZZ_pEXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); ZZ_pEX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(_NTL_ZZ_pEXMatrix& M_out, ZZ_pEX& U, ZZ_pEX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_ZZ_pEX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; //ZZ_pXMatrix M1; _NTL_ZZ_pEXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } ZZ_pEX Q; _NTL_ZZ_pEXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); ZZ_pEX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(ZZ_pEX& U, ZZ_pEX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_ZZ_pEXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); ZZ_pEX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(ZZ_pEX& d, const ZZ_pEX& u, const ZZ_pEX& v) { ZZ_pEX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_ZZ_pEX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } ZZ_pEX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } _NTL_ZZ_pEXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(ZZ_pE* a, long n) { long i, k; ZZ_pE b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a) // does a Horner evaluation { ZZ_pE acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_ZZ_pE bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long m = a.length(); if (b.length() != m) LogicError("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_ZZ_pE prod; prod = a; ZZ_pE t1, t2; long k, i; vec_ZZ_pE res; res.SetLength(m); for (k = 0; k < m; k++) { const ZZ_pE& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(ZZ_pEX& x, const vec_ZZ_pE& v, long low, long high, const vec_ZZ_pEX& H, long n, vec_ZZ_pX& t) { ZZ_pX s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_pE& h = H[i-low].rep; long m = h.length(); const ZZ_pX& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { if (deg(g) <= 0) { x = g; return; } ZZ_pEX s, t; vec_ZZ_pX scratch; SetSize(scratch, deg(F), 2*ZZ_pE::degree()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const ZZ_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(ZZ_pEXArgument& A, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) LogicError("build: bad args"); if (m > F.n) m = F.n; if (ZZ_pEXArgBound > 0) { double sz = ZZ_p::storage(); sz = sz*ZZ_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_pE); sz = sz/1024; m = min(m, long(ZZ_pEXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_CHEAP_THREAD_LOCAL long ZZ_pEXArgBound = 0; void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pEXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } ZZ_pEXArgument A; build(A, h, F, m); ZZ_pEX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } ZZ_pEXArgument A; build(A, h, F, m); ZZ_pEX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); ZZ_pEX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); ZZ_pEX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void ShiftSub(ZZ_pEX& U, const ZZ_pEX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { ZZ_pEX xx; TransMulMod(xx, to_ZZ_pEX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_ZZ_pE& x, const ZZ_pEX& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { if (k < 0 || deg(a) >= F.n) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pEXTransMultiplier M; build(M, H.H[m], F); ZZ_pEX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_ZZ_pE& x, const ZZ_pEX& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); ZZ_pEXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { ProjectPowers(x, to_ZZ_pEX(a), k, H, F); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ProjectPowers(x, to_ZZ_pEX(a), k, h, F); } void BerlekampMassey(ZZ_pEX& h, const vec_ZZ_pE& a, long m) { ZZ_pEX Lambda, Sigma, Temp; long L; ZZ_pE Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const ZZ_pEX& R) { vec_ZZ_pE x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); ZZ_pEX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ ZZ_pEX h2, h3; ZZ_pEX R; ZZ_pEXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); ZZ_pEX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F) { MinPolyMod(hh, g, F, F.n); } void diff(ZZ_pEX& x, const ZZ_pEX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(ZZ_pEX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; ZZ_pE t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } ZZ_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const ZZ_pEX& a, const ZZ_pEX& b) { if (IsZero(b)) return IsZero(a); ZZ_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); ZZ_pEX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 3); vec_ZZ_pEX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { ZZ_pEX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); ZZ_pEX d, xx, t; XGCD(d, xx, t, a, f); if (!IsOne(d)) InvModError("ZZ_pEX InvMod: can't compute multiplicative inverse"); x = xx; } long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvModStatus: bad args"); ZZ_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) LogicError("MulMod: bad args"); ZZ_pEX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("SqrMod: bad args"); ZZ_pEX t; sqr(t, a); rem(x, t, f); } void PowerXMod(ZZ_pEX& hh, const ZZ& e, const ZZ_pEXModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; ZZ_pEX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { ZZ_pEX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void power(ZZ_pEX& x, const ZZ_pEX& a, long e) { if (e < 0) { ArithmeticError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); ZZ_pEX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_ZZ_pE& S, const ZZ_pEXModulus& f) { long n = deg(f); ZZ_pEX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_ZZ_pE& S, const ZZ_pEX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); ZZ_pEX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ_pX acc, t; ZZ_pE t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f) { if (deg(f) < ZZ_pE::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(vec_ZZ_pE& S, const ZZ_pEXModulus& F) { if (F.method == ZZ_pEX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); InnerProduct(x, a.rep, *F.tracevec.val()); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; ZZ_pE lc; set(res); long n = max(deg(a),deg(b)) + 1; ZZ_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_ZZ_pX tmp; SetSize(tmp, n, 2*ZZ_pE::degree()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void resultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b) { PlainResultant(rres, a, b); } void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } ZZ_pE t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { ZZ_pE t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(ZZ_pEX& x, const vec_ZZ_p& v, long low, long high, const vec_ZZ_pEX& H, long n, vec_ZZ_pE& t) { ZZ_pE s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_pE& h = H[i-low].rep; long m = h.length(); const ZZ_p& w = v[i]; for (j = 0; j < m; j++) { mul(s, h[j], w); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } ZZ_pEX s, t; vec_ZZ_pE scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const ZZ_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pEXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_ZZ_p& tt, const vec_ZZ_pE& s, const vec_ZZ_p& proj) { long l = s.length(); tt.SetLength(l); ZZ_pXMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), ZZ_pE::modulus()); UpdateMap(tt[i], proj, M, ZZ_pE::modulus()); } } void ProjectedInnerProduct(ZZ_p& x, const vec_ZZ_pE& a, const vec_vec_ZZ_p& b) { long n = min(a.length(), b.length()); ZZ_p t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_ZZ_p& proj, const ZZ_pX& f) { long n = deg(f); if (n <= 0) LogicError("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_ZZ_p& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F, const vec_ZZ_p& proj) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pEXTransMultiplier M; build(M, H.H[m], F); vec_ZZ_pE s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_ZZ_p tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); ZZ_p* w = &x[i*m]; PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) ProjectedInnerProduct(w[j], H.H[j].rep, tt); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_ZZ_p& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F, const vec_ZZ_p& proj) { if (a.length() > F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); ZZ_pEXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const vec_ZZ_pE& R, const vec_ZZ_p& proj) { vec_ZZ_p x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) LogicError("MinPoly: bad args"); vec_ZZ_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_ZZ_p proj; PrecomputeProj(proj, ZZ_pE::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m, const vec_ZZ_p& proj) { long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) LogicError("MinPoly: bad args"); vec_ZZ_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(ZZ_pX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX h; ZZ_pEX h1; long n = F.n; if (m < 1 || m > n*ZZ_pE::degree()) LogicError("MinPoly: bad args"); vec_ZZ_p proj; PrecomputeProj(proj, ZZ_pE::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; ZZ_pX h2; ZZ_pEX h3; vec_ZZ_pE R; ZZ_pEXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { if (m < 1 || m > deg(F)*ZZ_pE::degree()) LogicError("IrredPoly: bad args"); vec_ZZ_pE R; R.SetLength(1); R[0] = 1; vec_ZZ_p proj; proj.SetLength(1); proj[0] = 1; DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-11.5.1/src/ZZ_pEXFactoring.cpp0000644417616742025610000006671514064716022020443 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static void IterPower(ZZ_pE& c, const ZZ_pE& a, long n) { ZZ_pE res; long i; res = a; for (i = 0; i < n; i++) power(res, res, ZZ_p::modulus()); c = res; } void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& ff) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SquareFreeDecomp: bad args"); ZZ_pEX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long k, d; long p = to_long(ZZ_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterPower(f.rep[k], r.rep[k*p], ZZ_pE::degree()-1); m = m*p; } } while (!finished); } static void AbsTraceMap(ZZ_pEX& h, const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX res, tmp; long k = NumBits(ZZ_pE::cardinality())-1; res = a; tmp = a; long i; for (i = 0; i < k-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void FrobeniusMap(ZZ_pEX& h, const ZZ_pEXModulus& F) { PowerXMod(h, ZZ_pE::cardinality(), F); } static void RecFindRoots(vec_ZZ_pE& x, const ZZ_pEX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pEX h; ZZ_pEX r; { ZZ_pEXModulus F; build(F, f); do { random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& ff) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } void split(ZZ_pEX& f1, ZZ_pEX& g1, ZZ_pEX& f2, ZZ_pEX& g2, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots, long lo, long mid) { long r = mid-lo+1; ZZ_pEXModulus F; build(F, f); vec_ZZ_pE lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; ZZ_pEX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } void RecFindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } ZZ_pEX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } void FindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } void IterFindFactors(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& g, const vec_ZZ_pE& roots) { long r = roots.length(); long i; ZZ_pEX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b) { if (d < 0) LogicError("TraceMap: bad args"); ZZ_pEX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(ZZ_pEX& y, const ZZ_pEX& h, long q, const ZZ_pEXModulus& F) { if (q < 0) LogicError("PowerCompose: bad args"); ZZ_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const ZZ_pEX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_CHEAP_THREAD_LOCAL long ZZ_pEX_BlockingFactor = 10; void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose) { vec_ZZ_pE roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } void EDFSplit(vec_ZZ_pEX& v, const ZZ_pEX& f, const ZZ_pEX& b, long d) { ZZ_pEX a, g, h; ZZ_pEXModulus F; vec_ZZ_pE roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } void RecEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose) { vec_ZZ_pEX v; long i; ZZ_pEX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { ZZ_pEX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& ff, const ZZ_pEX& bb, long d, long verbose) { ZZ_pEX f = ff; ZZ_pEX b = bb; if (!IsOne(LeadCoeff(f))) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& ff, long verbose) { ZZ_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_ZZ_pEX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } ZZ_pEX hh; vec_ZZ_pEX v; long i; for (i = 0; i < u.length(); i++) { const ZZ_pEX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("CanZass: bad args"); double t; vec_pair_ZZ_pEX_long sfd; vec_ZZ_pEX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); ZZ_pEX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } long BaseCase(const ZZ_pEX& h, long q, long a, const ZZ_pEXModulus& F) { long b, e; ZZ_pEX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(ZZ_pEX& y1, ZZ_pEX& y2, const ZZ_pEX& h, long q1, long q2, const ZZ_pEXModulus& F) { ZZ_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const ZZ_pEX& h, const ZZ_pEXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); ZZ_pEX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(ZZ_pE& root, const ZZ_pEX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pEXModulus F; ZZ_pEX h, h1, f; ZZ_pEX r; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const ZZ_pEX& h, long q, long a, const ZZ_pEXModulus& F) { long e; ZZ_pEX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const ZZ_pEX& h, const ZZ_pEXModulus& F, const FacVec& fvec) { long q1, q2; ZZ_pEX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const ZZ_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; FrobeniusMap(h, F); ZZ_pEX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const ZZ_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pEXModulus F; build(F, f); ZZ_pEX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); ZZ_pEXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; ZZ_pEX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_ZZ_pEX& h, const ZZ_pEX& f, const ZZ_pEX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { ZZ_pEX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(ZZ_pEX& x, const ZZ_pEX& f, const ZZ_pEX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_ZZ_pEX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_ZZ_pE a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(ZZ_pEX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(ZZ_pEX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { ZZ_pEX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(ZZ_pEX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(ZZ_pEX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (n == 1) { SetX(f); return; } ZZ_pEX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g) { ZZ_pEXModulus G; ZZ_pEX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_CHEAP_THREAD_LOCAL long ZZ_pEX_GCDTableSize = 4; NTL_CHEAP_THREAD_LOCAL double ZZ_pEXFileThresh = NTL_FILE_THRESH; static NTL_CHEAP_THREAD_LOCAL vec_ZZ_pEX *BabyStepFile=0; static NTL_CHEAP_THREAD_LOCAL vec_ZZ_pEX *GiantStepFile=0; static NTL_CHEAP_THREAD_LOCAL long use_files; static double CalcTableSize(long n, long k) { double sz = ZZ_p::storage(); sz = sz*ZZ_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz*n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_pE); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(ZZ_pEX& h1, const ZZ_pEX& f, const ZZ_pEX& h, long k, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } ZZ_pEXModulus F; build(F, f); ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; if (!use_files) { (*BabyStepFile).SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("baby", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const ZZ_pEX& f, const ZZ_pEX& h, long l, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } ZZ_pEXModulus F; build(F, f); ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); ZZ_pEX h1; h1 = h; long i; if (!use_files) { (*GiantStepFile).SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void NewAddFactor(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_ZZ_pEX_long& u, ZZ_pEX& f, const ZZ_pEXModulus& F, vec_ZZ_pEX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; ZZ_pEX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(ZZ_pEX& g, long gs, const ZZ_pEXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName("giant", gs)); NTL_INPUT_CHECK_ERR(s >> g); } else g = (*GiantStepFile)(gs); rem(g, g, F); } static void FetchBabySteps(vec_ZZ_pEX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName("baby", i)); NTL_INPUT_CHECK_ERR(s >> v[i]); } else v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_ZZ_pEX BabyStep; FetchBabySteps(BabyStep, k); vec_ZZ_pEX buf(INIT_SIZE, ZZ_pEX_GCDTableSize); ZZ_pEX f; f = ff; ZZ_pEXModulus F; build(F, f); ZZ_pEX g; ZZ_pEX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == ZZ_pEX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& ff, long k, long gs, const vec_ZZ_pEX& BabyStep, long verbose) { vec_ZZ_pEX buf(INIT_SIZE, ZZ_pEX_GCDTableSize); ZZ_pEX f; f = ff; ZZ_pEXModulus F; build(F, f); ZZ_pEX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == ZZ_pEX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_ZZ_pEX_long& factors, const vec_pair_ZZ_pEX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_ZZ_pEX BabyStep; long i; for (i = 0; i < u.length(); i++) { const ZZ_pEX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pEX h1; if (CalcTableSize(deg(f), k + l - 1) > ZZ_pEXFileThresh) use_files = 1; else use_files = 0; FileList flist; vec_ZZ_pEX local_BabyStepFile; vec_ZZ_pEX local_GiantStepFile; BabyStepFile = &local_BabyStepFile; GiantStepFile = &local_GiantStepFile; GenerateBabySteps(h1, f, h, k, flist, verbose); GenerateGiantSteps(f, h1, l, flist, verbose); vec_pair_ZZ_pEX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); } long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pEXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); ZZ_pEX h1; h1 = h; vec_ZZ_pEX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-11.5.1/src/ZZ_pX.cpp0000644417616742025610000022600214064716022016464 0ustar gid-shoupvpug-gid-shoupv#include #include #include // The mul & sqr routines use routines from ZZX, // which is faster for small degree polynomials. // Define this macro to revert to old strategy. #ifndef NTL_WIZARD_HACK #include #endif NTL_START_IMPL #if (defined(NTL_GMP_LIP)) #define KARX 200 #else #define KARX 80 #endif #define PAR_THRESH (4000.0) #define PAR_THRESH1 (20000.0) // Higher threshold for cheaper operations static inline bool BelowThresh(long n) { return double(n)*double(ZZ_p::ModulusSize()) < PAR_THRESH; } static inline bool BelowThresh1(long n) { return double(n)*double(ZZ_p::ModulusSize()) < PAR_THRESH1; } const ZZ_pX& ZZ_pX::zero() { static const ZZ_pX z; // GLOBAL (relies on C++11 thread-safe init) return z; } ZZ_pX& ZZ_pX::operator=(long a) { conv(*this, a); return *this; } ZZ_pX& ZZ_pX::operator=(const ZZ_p& a) { conv(*this, a); return *this; } istream& operator>>(istream& s, ZZ_pX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const ZZ_pX& a) { return s << a.rep; } void ZZ_pX::normalize() { long n; const ZZ_p* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const ZZ_pX& a) { return a.rep.length() == 0; } long IsOne(const ZZ_pX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(ZZ_p& x, const ZZ_pX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { NTL_ZZ_pRegister(aa); aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(ZZ_pX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_ZZ_pRegister(T); conv(T, a); SetCoeff(x, i, T); } } void SetCoeff(ZZ_pX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(ZZ_pX& x) { clear(x); SetCoeff(x, 1); } long IsX(const ZZ_pX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const ZZ_p& coeff(const ZZ_pX& a, long i) { if (i < 0 || i > deg(a)) return ZZ_p::zero(); else return a.rep[i]; } const ZZ_p& LeadCoeff(const ZZ_pX& a) { if (IsZero(a)) return ZZ_p::zero(); else return a.rep[deg(a)]; } const ZZ_p& ConstTerm(const ZZ_pX& a) { if (IsZero(a)) return ZZ_p::zero(); else return a.rep[0]; } void conv(ZZ_pX& x, const ZZ_p& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; // note: if a aliases x.rep[i], i > 0, this code // will still work, since is is assumed that // SetLength(1) will not relocate or destroy x.rep[i] } } void conv(ZZ_pX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } } void conv(ZZ_pX& x, const ZZ& a) { if (IsZero(a)) clear(x); else { NTL_ZZ_pRegister(T); conv(T, a); conv(x, T); } } void conv(ZZ_pX& x, const vec_ZZ_p& a) { x.rep = a; x.normalize(); } void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_p *ap, *bp; ZZ_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_p *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_p *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(ZZ_pX& x, const ZZ_pX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const ZZ_p *ap, *bp; ZZ_p* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x ZZ_p *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const ZZ_p *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(ZZ_pX& x, const ZZ_pX& a, long b) { if (b == 0) { x = a; return; } if (a.rep.length() == 0) { x.rep.SetLength(1); x.rep[0] = b; negate(x.rep[0], x.rep[0]); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void sub(ZZ_pX& x, long a, const ZZ_pX& b) { NTL_ZZ_pRegister(T); T = a; negate(x, b); add(x, x, T); } void negate(ZZ_pX& x, const ZZ_pX& a) { long n = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } #if (!defined(NTL_WIZARD_HACK) && defined(NTL_GMP_LIP)) // This only seems to help if we have GMP void mul(ZZ_pX& c, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(a) || IsZero(b)) { clear(c); return; } if (&a == &b) { sqr(c, a); return; } long k = ZZ_p::ModulusSize(); long s = min(deg(a), deg(b)) + 1; if (s == 1 || (k == 1 && s < 40) || (k == 2 && s < 20) || (k == 3 && s < 12) || (k <= 5 && s < 8) || (k <= 12 && s < 4) ) { PlainMul(c, a, b); } else if (s < KARX) { ZZX A, B, C; conv(A, a); conv(B, b); KarMul(C, A, B); conv(c, C); } else { long mbits; mbits = NumBits(ZZ_p::modulus()); // long nt = AvailableThreads(); // SSMul is now fully thread boosted double rat = SSRatio(deg(a), mbits, deg(b), mbits); if ( (k >= 106 && rat < 1.50) || (k >= 212 && rat < 1.75) ) { SSMul(c, a, b); } else { FFTMul(c, a, b); } } } void sqr(ZZ_pX& c, const ZZ_pX& a) { if (IsZero(a)) { clear(c); return; } long k = ZZ_p::ModulusSize(); long s = deg(a) + 1; if (s == 1 || (k == 1 && s < 50) || (k == 2 && s < 25) || (k == 3 && s < 25) || (k <= 6 && s < 12) || (k <= 8 && s < 8) || (k == 9 && s < 6) || (k <= 30 && s < 4) ) { PlainSqr(c, a); } else if (s < 80) { ZZX C, A; conv(A, a); KarSqr(C, A); conv(c, C); } else { long mbits; mbits = NumBits(ZZ_p::modulus()); // long nt = AvailableThreads(); // SSMul is now fully thread boosted double rat = SSRatio(deg(a), mbits, deg(a), mbits); if ( (k >= 53 && rat < 1.20) || (k >= 106 && rat < 1.30) || (k >= 212 && rat < 1.75) ) { SSSqr(c, a); } else { FFTSqr(c, a); } } } #else void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { if (&a == &b) { sqr(x, a); return; } if (deg(a) > NTL_ZZ_pX_FFT_CROSSOVER && deg(b) > NTL_ZZ_pX_FFT_CROSSOVER) FFTMul(x, a, b); else PlainMul(x, a, b); } void sqr(ZZ_pX& x, const ZZ_pX& a) { if (deg(a) > NTL_ZZ_pX_FFT_CROSSOVER) FFTSqr(x, a); else PlainSqr(x, a); } #endif void PlainMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } if (da == 0) { mul(x, b, a.rep[0]); return; } if (db == 0) { mul(x, a, b.rep[0]); return; } long d = da+db; const ZZ_p *ap, *bp; ZZ_p *xp; ZZ_pX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void PlainSqr(ZZ_pX& x, const ZZ_pX& a) { long da = deg(a); if (da < 0) { clear(x); return; } long d = 2*da; const ZZ_p *ap; ZZ_p *xp; ZZ_pX la; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; long m, m2; NTL_ZZRegister(t); NTL_ZZRegister(accum); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(ap[i-j])); add(accum, accum, t); } add(accum, accum, accum); if (m & 1) { sqr(t, rep(ap[jmax + 1])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1, ZZ_p::ExtendedModulusSize()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& x) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& x) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pX: division by zero"); if (da < db) { r = a; clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ_p *qp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pX: division by zero"); if (da < db) { clear(q); return; } ZZ_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1 - db, ZZ_p::ExtendedModulusSize()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long da, db, dq, i, j, LCIsOne; const ZZ_p *bp; ZZ *xp; ZZ_p LCInv, t; NTL_ZZRegister(s); da = deg(a); db = deg(b); if (db < 0) ArithmeticError("ZZ_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } ZZVec x(da + 1, ZZ_p::ExtendedModulusSize()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } NTL_TBDECL_static(MulAux)(ZZ_p* xp, const ZZ_p* ap, const ZZ_p& t, long n) { for (long i = 0; i < n; i++) mul(xp[i], ap[i], t); } #ifdef NTL_THREAD_BOOST static void MulAux(ZZ_p* xp, const ZZ_p* ap, const ZZ_p& t, long n) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(n)) { basic_MulAux(xp, ap, t, n); return; } ZZ_pContext local_context; local_context.save(); pool->exec_range(n, [xp, ap, &t, &local_context](long first, long last) { local_context.restore(); for (long i = first; i < last; i++) mul(xp[i], ap[i], t); } ); } #endif void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b) { if (IsZero(b)) { clear(x); return; } if (IsOne(b)) { x = a; return; } NTL_ZZ_pRegister(t); long da; const ZZ_p *ap; ZZ_p* xp; t = b; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); MulAux(xp, ap, t, da+1); x.normalize(); } void mul(ZZ_pX& x, const ZZ_pX& a, long b) { NTL_ZZ_pRegister(T); conv(T, b); mul(x, a, T); } void PlainGCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; ZZ_pX u(INIT_SIZE, n), v(INIT_SIZE, n); ZZVec tmp(n, ZZ_p::ExtendedModulusSize()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainXGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; ZZ_pX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) LogicError("MulMod: bad args"); ZZ_pX t; mul(t, a, b); rem(x, t, f); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("SqrMod: bad args"); ZZ_pX t; sqr(t, a); rem(x, t, f); } void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); ZZ_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) InvModError("ZZ_pX InvMod: can't compute multiplicative inverse"); } long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvModStatus: bad args"); ZZ_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } NTL_TBDECL_static(MulByXModAux1)(long n, ZZ_p *hh, const ZZ_p* aa, const ZZ_p *ff, const ZZ_p& z) { NTL_ZZ_pRegister(t); for (long i = n-1; i >= 1; i--) { // hh[i] = aa[i-1] + z*ff[i] mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } } #ifdef NTL_THREAD_BOOST static void MulByXModAux1(long n, ZZ_p *hh, const ZZ_p* aa, const ZZ_p *ff, const ZZ_p& z) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || hh == aa || BelowThresh(n)) { // Careful! can't parallelize if hh == aa basic_MulByXModAux1(n, hh, aa, ff, z); return; } ZZ_pContext local_context; local_context.save(); pool->exec_range(n-1, [n, hh, aa, ff, &z, &local_context] (long first, long last) { local_context.restore(); NTL_ZZ_pRegister(t); for (long idx = first; idx < last; idx++) { long i = n-1-idx; // hh[i] = aa[i-1] + z*ff[i] mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } } ); } #endif static void MulByXModAux(ZZ_pX& h, const ZZ_pX& a, const ZZ_pX& f) { long i, n, m; ZZ_p* hh; const ZZ_p *aa, *ff; NTL_ZZ_pRegister(z); n = deg(f); m = deg(a); if (m >= n || n == 0) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); MulByXModAux1(n, hh, aa, ff, z); mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(ZZ_pX& h, const ZZ_pX& a, const ZZ_pX& f) { if (&h == &f) { ZZ_pX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(ZZ_pX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void FFTRep::DoSetSize(long NewK, long NewNumPrimes) { if (NewK < -1) LogicError("bad arg to FFTRep::SetSize()"); if (NewK >= NTL_BITS_PER_LONG-1) ResourceError("bad arg to FFTRep::SetSize()"); if (NewK == -1) { k = -1; return; } if (NewNumPrimes == 0) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); NewNumPrimes = FFTInfo->NumPrimes; } if (MaxK >= 0 && NumPrimes != NewNumPrimes) LogicError("FFTRep: inconsistent use"); if (NewK <= MaxK) { k = NewK; return; } tbl.SetDims(NewNumPrimes, 1L << NewK); NumPrimes = NewNumPrimes; k = MaxK = NewK; } void FFTRep::SetSize(long NewK) { DoSetSize(NewK, 0); } FFTRep& FFTRep::operator=(const FFTRep& R) { if (this == &R) return *this; if (MaxK >= 0 && R.MaxK >= 0 && NumPrimes != R.NumPrimes) LogicError("FFTRep: inconsistent use"); if (R.k < 0) { k = -1; len = 0; return *this; } DoSetSize(R.k, R.NumPrimes); len = R.len; long i, j; for (i = 0; i < NumPrimes; i++) for (j = 0; j < len; j++) tbl[i][j] = R.tbl[i][j]; return *this; } void ZZ_pXModRep::SetSize(long NewN) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); if (NewN < 0) LogicError("bad arg to ZZ_pXModRep::SetSize()"); if (NewN <= MaxN) { n = NewN; return; } tbl.SetDims(FFTInfo->NumPrimes, NewN); n = MaxN = NewN; NumPrimes = FFTInfo->NumPrimes; } // FIXME: maybe I could put this is scratch space associated // with the current modulus static inline vec_long& ModularRepBuf() { NTL_TLS_LOCAL(vec_long, t); return t; } void ToModularRep(vec_long& x, const ZZ_p& a, const ZZ_pFFTInfoT *FFTInfo, ZZ_pTmpSpaceT *TmpSpace) { FFTInfo->rem_struct.eval(&x[0], rep(a), TmpSpace->rem_tmp_vec); } void FromModularRep(ZZ_p& x, vec_long& avec, const ZZ_pFFTInfoT *FFTInfo, ZZ_pTmpSpaceT *TmpSpace) // NOTE: a gets destroyed { NTL_ZZRegister(t); long * NTL_RESTRICT a = avec.elts(); if (FFTInfo->crt_struct.special()) { FFTInfo->crt_struct.eval(t, a, TmpSpace->crt_tmp_vec); x.LoopHole() = t; return; } long nprimes = FFTInfo->NumPrimes; const long *u = FFTInfo->u.elts(); const long *prime = FFTInfo->prime.elts(); const mulmod_precon_t *uqinv = FFTInfo->uqinv.elts(); const double *prime_recip = FFTInfo->prime_recip.elts(); double y = 0.0; for (long i = 0; i < nprimes; i++) { long r = MulModPrecon(a[i], u[i], prime[i], uqinv[i]); a[i] = r; y += double(r)*prime_recip[i]; } long q = long(y + 0.5); FFTInfo->crt_struct.eval(t, a, TmpSpace->crt_tmp_vec); MulAddTo(t, FFTInfo->MinusMModP, q); // TODO: this MulAddTo could be folded into the above // crt_struct.eval as just another product to accumulate... // but, savings would be marginal and a number of interfaces // would have to be modified... // montgomery FFTInfo->reduce_struct.eval(x.LoopHole(), t); } NTL_TBDECL(ToFFTRep_trunc)(FFTRep& y, const ZZ_pX& x, long k, long len, long lo, long hi) // computes an n = 2^k point convolution. // if deg(x) >= 2^k, then x is first reduced modulo X^n-1. { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long n, i, j, m, j1; vec_long& t = ModularRepBuf(); if (k > FFTInfo->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to ToFFTRep"); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); hi = min(hi, deg(x)); y.SetSize(k); n = 1L << k; y.len = len = FFTRoundUp(len, k); m = max(hi-lo + 1, 0); long ilen = FFTRoundUp(m, k); const ZZ_p *xx = x.rep.elts(); if (n >= m) { for (j = 0; j < m; j++) { ToModularRep(t, xx[j+lo], FFTInfo, TmpSpace); for (i = 0; i < nprimes; i++) { y.tbl[i][j] = t[i]; } } if (ilen > m) { for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; for (j = m; j < ilen; j++) { yp[j] = 0; } } } } else { NTL_ZZ_pRegister(accum); for (j = 0; j < n; j++) { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum, FFTInfo, TmpSpace); for (i = 0; i < nprimes; i++) { y.tbl[i][j] = t[i]; } } } // FIXME: something to think about...part of the above logic // is essentially a matrix transpose, which could lead to bad // cache performance. I don't really know if that is an issue. for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd_trunc(yp, yp, k, i, len, ilen); } } #ifdef NTL_THREAD_BOOST void ToFFTRep_trunc(FFTRep& y, const ZZ_pX& x, long k, long len, long lo, long hi) // computes an n = 2^k point convolution. // if deg(x) >= 2^k, then x is first reduced modulo X^n-1. { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << k)) { basic_ToFFTRep_trunc(y, x, k, len, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long n, m; if (k > FFTInfo->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to ToFFTRep"); long nprimes = FFTInfo->NumPrimes; hi = min(hi, deg(x)); y.SetSize(k); n = 1L << k; y.len = len = FFTRoundUp(len, k); m = max(hi-lo + 1, 0); long ilen = FFTRoundUp(m, k); const ZZ_p *xx = x.rep.elts(); ZZ_pContext local_context; local_context.save(); if (n >= m) { pool->exec_range(m, [lo, xx, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long j = first; j < last; j++) { ToModularRep(t, xx[j+lo], FFTInfo, TmpSpace); for (long i = 0; i < nprimes; i++) { y.tbl[i][j] = t[i]; } } } ); } else { pool->exec_range(n, [lo, m, n, xx, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); NTL_ZZ_pRegister(accum); for (long j = first; j < last; j++) { accum = xx[j+lo]; for (long j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum, FFTInfo, TmpSpace); for (long i = 0; i < nprimes; i++) { y.tbl[i][j] = t[i]; } } } ); } // FIXME: something to think about...part of the above logic // is essentially a matrix transpose, which could lead to bad // cache performance. I don't really know if that is an issue. pool->exec_range(nprimes, [&y, m, n, k, len, ilen](long first, long last) { for (long i = first; i < last; i++) { long *yp = &y.tbl[i][0]; for (long j = m; j < ilen; j++) yp[j] = 0; FFTFwd_trunc(yp, yp, k, i, len, ilen); } } ); } #endif NTL_TBDECL(RevToFFTRep)(FFTRep& y, const vec_ZZ_p& x, long k, long lo, long hi, long offset) // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long n, i, j, m, j1; vec_long& t = ModularRepBuf(); NTL_ZZ_pRegister(accum); if (k > FFTInfo->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to ToFFTRep"); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); hi = min(hi, x.length()-1); y.SetSize(k); n = 1L << k; y.len = n; m = max(hi-lo + 1, 0); const ZZ_p *xx = x.elts(); offset = offset & (n-1); for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < nprimes; i++) y.tbl[i][offset] = 0; } else { accum = xx[j+lo]; for (j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum, FFTInfo, TmpSpace); for (i = 0; i < nprimes; i++) { y.tbl[i][offset] = t[i]; } } offset = (offset + 1) & (n-1); } for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trans(yp, yp, k, i); } } #ifdef NTL_THREAD_BOOST void RevToFFTRep(FFTRep& y, const vec_ZZ_p& x, long k, long lo, long hi, long offset) // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << k)) { basic_RevToFFTRep(y, x, k, lo, hi, offset); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long n, m; if (k > FFTInfo->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to ToFFTRep"); long nprimes = FFTInfo->NumPrimes; hi = min(hi, x.length()-1); y.SetSize(k); n = 1L << k; y.len = n; m = max(hi-lo + 1, 0); const ZZ_p *xx = x.elts(); offset = offset & (n-1); ZZ_pContext local_context; local_context.save(); pool->exec_range(n, [lo, m, n, offset, xx, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); long local_offset = (offset + first) & (n-1); NTL_ZZ_pRegister(accum); for (long j = first; j < last; j++) { if (j >= m) { for (long i = 0; i < nprimes; i++) y.tbl[i][local_offset] = 0; } else { accum = xx[j+lo]; for (long j1 = j + n; j1 < m; j1 += n) add(accum, accum, xx[j1+lo]); ToModularRep(t, accum, FFTInfo, TmpSpace); for (long i = 0; i < nprimes; i++) { y.tbl[i][local_offset] = t[i]; } } local_offset = (local_offset + 1) & (n-1); } } ); pool->exec_range(nprimes, [&y, k](long first, long last) { for (long i = first; i < last; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trans(yp, yp, k, i); } } ); } #endif NTL_TBDECL(FromFFTRep)(ZZ_pX& x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long k, n, i, j, l; vec_long& t = ModularRepBuf(); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromFFTRep: bad len 1"); for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trunc(yp, yp, k, i, len); } x.rep.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < nprimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x.rep[j], t, FFTInfo, TmpSpace); } x.normalize(); } #ifdef NTL_THREAD_BOOST void FromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << y.k)) { basic_FromFFTRep(x, y, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, n, l; long nprimes = FFTInfo->NumPrimes; k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromFFTRep: bad len 2"); pool->exec_range(nprimes, [&y, k, len](long first, long last) { for (long i = first; i < last; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trunc(yp, yp, k, i, len); } } ); x.rep.SetLength(l); ZZ_p *xx = x.rep.elts(); ZZ_pContext local_context; local_context.save(); pool->exec_range(l, [lo, xx, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long j = first; j < last; j++) { for (long i = 0; i < nprimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(xx[j], t, FFTInfo, TmpSpace); } } ); x.normalize(); } #endif NTL_TBDECL(RevFromFFTRep)(vec_ZZ_p& x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long k, n, i, j, l; vec_long& t = ModularRepBuf(); k = y.k; n = (1L << k); if (y.len != n) LogicError("RevFromFFTRep: bad len"); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd_trans(yp, yp, k, i); } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < nprimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(x[j], t, FFTInfo, TmpSpace); } } #ifdef NTL_THREAD_BOOST void RevFromFFTRep(vec_ZZ_p& x, FFTRep& y, long lo, long hi) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << y.k)) { basic_RevFromFFTRep(x, y, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, n, l; long nprimes = FFTInfo->NumPrimes; k = y.k; n = (1L << k); if (y.len != n) LogicError("RevFromFFTRep: bad len"); pool->exec_range(nprimes, [&y, k](long first, long last) { for (long i = first; i < last; i++) { long *yp = &y.tbl[i][0]; FFTFwd_trans(yp, yp, k, i); } } ); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.SetLength(l); ZZ_p *xx = x.elts(); ZZ_pContext local_context; local_context.save(); pool->exec_range(l, [lo, xx, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long j = first; j < last; j++) { for (long i = 0; i < nprimes; i++) t[i] = y.tbl[i][j+lo]; FromModularRep(xx[j], t, FFTInfo, TmpSpace); } } ); } #endif NTL_TBDECL(NDFromFFTRep)(ZZ_pX& x, const FFTRep& y, long lo, long hi, FFTRep& z) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long k, n, i, j, l; vec_long& t = ModularRepBuf(); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromFFTRep: bad len 3"); z.SetSize(k); for (i = 0; i < nprimes; i++) { long *zp = &z.tbl[i][0]; const long *yp = &y.tbl[i][0]; FFTRev1_trunc(zp, yp, k, i, len); } x.rep.SetLength(l); for (j = 0; j < l; j++) { for (i = 0; i < nprimes; i++) t[i] = z.tbl[i][j+lo]; FromModularRep(x.rep[j], t, FFTInfo, TmpSpace); } x.normalize(); } #ifdef NTL_THREAD_BOOST void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi, FFTRep& z) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << y.k)) { basic_NDFromFFTRep(x, y, lo, hi, z); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, n, l; long nprimes = FFTInfo->NumPrimes; k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromFFTRep: bad len 4"); z.SetSize(k); pool->exec_range(nprimes, [&y, &z, k, len](long first, long last) { for (long i = first; i < last; i++) { long *zp = &z.tbl[i][0]; const long *yp = &y.tbl[i][0]; FFTRev1_trunc(zp, yp, k, i, len); } } ); x.rep.SetLength(l); ZZ_p *xx = x.rep.elts(); ZZ_pContext local_context; local_context.save(); pool->exec_range(l, [lo, xx, &z, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long j = first; j < last; j++) { for (long i = 0; i < nprimes; i++) t[i] = z.tbl[i][j+lo]; FromModularRep(xx[j], t, FFTInfo, TmpSpace); } } ); x.normalize(); } #endif void NDFromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi) { FFTRep z; NDFromFFTRep(x, y, lo, hi, z); } NTL_TBDECL(FromFFTRep)(ZZ_p* x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long k, n, i, j; vec_long& t = ModularRepBuf(); k = y.k; n = (1L << k); //if (y.len <= min(hi, n-1)) LogicError("FromFFTRep: bad len"); if (y.len != n) LogicError("FromFFTRep: bad len 5"); long nprimes = FFTInfo->NumPrimes; t.SetLength(nprimes); for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } for (j = lo; j <= hi; j++) { if (j >= n) clear(x[j-lo]); else { for (i = 0; i < nprimes; i++) t[i] = y.tbl[i][j]; FromModularRep(x[j-lo], t, FFTInfo, TmpSpace); } } } #ifdef NTL_THREAD_BOOST void FromFFTRep(ZZ_p* x, FFTRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << y.k)) { basic_FromFFTRep(x, y, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, n, l; k = y.k; n = (1L << k); //if (y.len <= min(hi, n-1)) LogicError("FromFFTRep: bad len"); if (y.len != n) LogicError("FromFFTRep: bad len 6"); long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&y, k](long first, long last) { for (long i = first; i < last; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } } ); ZZ_pContext local_context; local_context.save(); pool->exec_range(hi-lo+1, [n, lo, x, &y, nprimes, &local_context, FFTInfo] (long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long idx = first; idx < last; idx++) { long j = lo + idx; if (j >= n) clear(x[j-lo]); else { for (long i = 0; i < nprimes; i++) t[i] = y.tbl[i][j]; FromModularRep(x[j-lo], t, FFTInfo, TmpSpace); } } } ); } #endif NTL_TBDECL(mul)(FFTRep& z, const FFTRep& x, const FFTRep& y) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; for (i = 0; i < nprimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); mulmod_t qinv = GetFFTPrimeInv(i); for (j = 0; j < len; j++) zp[j] = NormalizedMulMod(xp[j], yp[j], q, qinv); } } #ifdef NTL_THREAD_BOOST void mul(FFTRep& z, const FFTRep& x, const FFTRep& y) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh1(1L << x.k)) { basic_mul(z, x, y); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&x, &y, &z, len](long first, long last) { for (long i = first; i < last; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); mulmod_t qinv = GetFFTPrimeInv(i); for (long j = 0; j < len; j++) zp[j] = NormalizedMulMod(xp[j], yp[j], q, qinv); } } ); } #endif NTL_TBDECL(sub)(FFTRep& z, const FFTRep& x, const FFTRep& y) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; for (i = 0; i < nprimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (j = 0; j < len; j++) zp[j] = SubMod(xp[j], yp[j], q); } } #ifdef NTL_THREAD_BOOST void sub(FFTRep& z, const FFTRep& x, const FFTRep& y) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh1(1L << x.k)) { basic_sub(z, x, y); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&x, &y, &z, len](long first, long last) { for (long i = first; i < last; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (long j = 0; j < len; j++) zp[j] = SubMod(xp[j], yp[j], q); } } ); } #endif NTL_TBDECL(add)(FFTRep& z, const FFTRep& x, const FFTRep& y) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; for (i = 0; i < nprimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (j = 0; j < len; j++) zp[j] = AddMod(xp[j], yp[j], q); } } #ifdef NTL_THREAD_BOOST void add(FFTRep& z, const FFTRep& x, const FFTRep& y) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh1(1L << x.k)) { basic_add(z, x, y); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long k; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; z.SetSize(k); long len = z.len = min(x.len, y.len); long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&x, &y, &z, len](long first, long last) { for (long i = first; i < last; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (long j = 0; j < len; j++) zp[j] = AddMod(xp[j], yp[j], q); } } ); } #endif NTL_TBDECL(reduce)(FFTRep& x, const FFTRep& a, long k) // reduces a 2^l point FFT-rep to a 2^k point FFT-rep // input may alias output { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long i, j, l, n; long* xp; const long* ap; l = a.k; n = 1L << k; if (l < k) LogicError("reduce: bad operands"); if (a.len < n) LogicError("reduce: bad len"); x.SetSize(k); x.len = n; if (&x == &a) return; long nprimes = FFTInfo->NumPrimes; for (i = 0; i < nprimes; i++) { ap = &a.tbl[i][0]; xp = &x.tbl[i][0]; for (j = 0; j < n; j++) xp[j] = ap[j]; } } #ifdef NTL_THREAD_BOOST void reduce(FFTRep& x, const FFTRep& a, long k) // reduces a 2^l point FFT-rep to a 2^k point FFT-rep // input may alias output { BasicThreadPool *pool = GetThreadPool(); if (&x == &a || !pool || pool->active() || pool->NumThreads() == 1 || BelowThresh1(1L << k)) { basic_reduce(x, a, k); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long l, n; l = a.k; n = 1L << k; if (l < k) LogicError("reduce: bad operands"); if (a.len < n) LogicError("reduce: bad len"); x.SetSize(k); x.len = n; long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&x, &a, n, l, k](long first, long last) { for (long i = first; i < last; i++) { const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (long j = 0; j < n; j++) xp[j] = ap[j]; } } ); } #endif NTL_TBDECL(AddExpand)(FFTRep& x, const FFTRep& a) // x = x + (an "expanded" version of a) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long i, j, l, k, n; l = x.k; k = a.k; n = 1L << k; if (l < k) LogicError("AddExpand: bad args"); if (a.len != n) LogicError("AddExpand: bad len"); if (x.len < n) LogicError("AddExpand: bad len"); long nprimes = FFTInfo->NumPrimes; for (i = 0; i < nprimes; i++) { long q = GetFFTPrime(i); const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (j = 0; j < n; j++) { xp[j] = AddMod(xp[j], ap[j], q); } } } #ifdef NTL_THREAD_BOOST void AddExpand(FFTRep& x, const FFTRep& a) // x = x + (an "expanded" version of a) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh1(1L << a.k)) { basic_AddExpand(x, a); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long l, k, n; l = x.k; k = a.k; n = 1L << k; if (l < k) LogicError("AddExpand: bad args"); if (a.len != n) LogicError("AddExpand: bad len"); if (x.len < n) LogicError("AddExpand: bad len"); long nprimes = FFTInfo->NumPrimes; pool->exec_range(nprimes, [&x, &a, n, l, k](long first, long last) { for (long i = first; i < last; i++) { long q = GetFFTPrime(i); const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (long j = 0; j < n; j++) { xp[j] = AddMod(xp[j], ap[j], q); } } } ); } #endif NTL_TBDECL(ToZZ_pXModRep)(ZZ_pXModRep& y, const ZZ_pX& x, long lo, long hi) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long n, i, j; vec_long& t = ModularRepBuf(); long nprimes = FFTInfo->NumPrimes; t.SetLength(FFTInfo->NumPrimes); if (lo < 0) LogicError("bad arg to ToZZ_pXModRep"); hi = min(hi, deg(x)); n = max(hi-lo+1, 0); y.SetSize(n); const ZZ_p *xx = x.rep.elts(); for (j = 0; j < n; j++) { ToModularRep(t, xx[j+lo], FFTInfo, TmpSpace); for (i = 0; i < nprimes; i++) y.tbl[i][j] = t[i]; } } #ifdef NTL_THREAD_BOOST void ToZZ_pXModRep(ZZ_pXModRep& y, const ZZ_pX& x, long lo, long hi) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(max(hi-lo+1,0))) { basic_ToZZ_pXModRep(y, x, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long n; long nprimes = FFTInfo->NumPrimes; if (lo < 0) LogicError("bad arg to ToZZ_pXModRep"); hi = min(hi, deg(x)); n = max(hi-lo+1, 0); y.SetSize(n); const ZZ_p *xx = x.rep.elts(); ZZ_pContext local_context; local_context.save(); pool->exec_range(n, [lo, xx, &y, nprimes, &local_context, FFTInfo](long first, long last) { local_context.restore(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); // TmpSpace is thread local! vec_long& t = ModularRepBuf(); t.SetLength(nprimes); for (long j = first; j < last; j++) { ToModularRep(t, xx[j+lo], FFTInfo, TmpSpace); for (long i = 0; i < nprimes; i++) y.tbl[i][j] = t[i]; } } ); } #endif NTL_TBDECL(ToFFTRep)(FFTRep& x, const ZZ_pXModRep& a, long k, long lo, long hi) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long n, m, i, j; if (k < 0 || lo < 0) LogicError("bad args to ToFFTRep"); if (hi > a.n-1) hi = a.n-1; n = 1L << k; m = max(hi-lo+1, 0); if (m > n) LogicError("bad args to ToFFTRep"); x.SetSize(k); x.len = n; long nprimes = FFTInfo->NumPrimes; if (m == 0) { for (i = 0; i < nprimes; i++) { long *xp = &x.tbl[i][0]; for (j = m; j < n; j++) xp[j] = 0; } } else { for (i = 0; i < nprimes; i++) { long *xp = &x.tbl[i][0]; long *ap = &a.tbl[i][0]; for (j = 0; j < m; j++) xp[j] = ap[lo+j]; for (j = m; j < n; j++) xp[j] = 0; FFTFwd(xp, xp, k, i); } } } #ifdef NTL_THREAD_BOOST void ToFFTRep(FFTRep& x, const ZZ_pXModRep& a, long k, long lo, long hi) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1 || BelowThresh(1L << k)) { basic_ToFFTRep(x, a, k, lo, hi); return; } const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long n, m; if (k < 0 || lo < 0) LogicError("bad args to ToFFTRep"); if (hi > a.n-1) hi = a.n-1; n = 1L << k; m = max(hi-lo+1, 0); if (m > n) LogicError("bad args to ToFFTRep"); x.SetSize(k); x.len = n; long nprimes = FFTInfo->NumPrimes; if (m == 0) { for (long i = 0; i < nprimes; i++) { long *xp = &x.tbl[i][0]; for (long j = m; j < n; j++) xp[j] = 0; } } else { pool->exec_range(nprimes, [&x, &a, lo, m, n, k](long first, long last) { for (long i = first; i < last; i++) { long *xp = &x.tbl[i][0]; long *ap = &a.tbl[i][0]; for (long j = 0; j < m; j++) xp[j] = ap[lo+j]; for (long j = m; j < n; j++) xp[j] = 0; FFTFwd(xp, xp, k, i); } } ); } } #endif void FromFFTRep(ZZ_pXModRep& x, const FFTRep& a) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); long nprimes = FFTInfo->NumPrimes; long k = a.k; long n = 1L << k; if (a.len != n) LogicError("FromFFTRep: bad len 7"); x.SetSize(n); for (long i = 0; i < nprimes; i++) { long *xp = &x.tbl[i][0]; long *ap = &a.tbl[i][0]; FFTRev1(xp, ap, k, i); } } void FromZZ_pXModRep(ZZ_pX& x, const ZZ_pXModRep& a, long lo, long hi) { const ZZ_pFFTInfoT *FFTInfo = ZZ_p::GetFFTInfo(); ZZ_pTmpSpaceT *TmpSpace = ZZ_p::GetTmpSpace(); long n = a.n; long nprimes = FFTInfo->NumPrimes; vec_long& t = ModularRepBuf(); t.SetLength(nprimes); hi = min(hi, n-1); long l = hi-lo+1; l = max(l, 0); x.rep.SetLength(l); for (long j = 0; j < l; j++) { for (long i = 0; i < nprimes; i++) t[i] = a.tbl[i][j+lo]; FromModularRep(x.rep[j], t, FFTInfo, TmpSpace); } x.normalize(); } void FFTMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long da = deg(a); long db = deg(b); long d = da+db; long k = NextPowerOfTwo(d+1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep_trunc(R1, a, k, d+1); ToFFTRep_trunc(R2, b, k, d+1); mul(R1, R1, R2); FromFFTRep(x, R1, 0, d); } void FFTSqr(ZZ_pX& x, const ZZ_pX& a) { if (IsZero(a)) { clear(x); return; } long da = deg(a); long d = 2*da; long k = NextPowerOfTwo(d+1); FFTRep R1(INIT_SIZE, k); ToFFTRep_trunc(R1, a, k, d+1); mul(R1, R1, R1); FromFFTRep(x, R1, 0, d); } void CopyReverse(ZZ_pX& x, const ZZ_pX& a, long lo, long hi) // x[0..hi-lo] = reverse(a[lo..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void copy(ZZ_pX& x, const ZZ_pX& a, long lo, long hi) // x[0..hi-lo] = a[lo..hi], with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const ZZ_p* ap = a.rep.elts(); ZZ_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = lo + i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void rem21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { x = a; return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainRem(x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-2, 2*n-4); ToFFTRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromFFTRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const ZZ_p* aa = a.rep.elts(); const ZZ_p* ss = P1.rep.elts(); ZZ_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); } void DivRem21(ZZ_pX& q, ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { x = a; clear(q); return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDivRem(q, x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n), qq; ToFFTRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-2, 2*n-4); qq = P1; ToFFTRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromFFTRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const ZZ_p* aa = a.rep.elts(); const ZZ_p* ss = P1.rep.elts(); ZZ_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); q = qq; } void div21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da, n; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < n) { clear(x); return; } if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDiv(x, a, F.f); return; } FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromFFTRep(x, R1, n-2, 2*n-4); } void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("rem: unitialized modulus"); if (da <= 2*n-2) { rem21(x, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainRem(x, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); rem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("uninitialized modulus"); if (da <= 2*n-2) { DivRem21(q, r, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDivRem(q, r, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); ZZ_pX qbuf(INIT_SIZE, n-1); ZZ_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); DivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("uninitialized modulus"); if (da <= 2*n-2) { div21(q, a, F); return; } else if (!F.UseFFT || da - n <= NTL_ZZ_pX_FFT_CROSSOVER) { PlainDiv(q, a, F.f); return; } ZZ_pX buf(INIT_SIZE, 2*n-1); ZZ_pX qbuf(INIT_SIZE, n-1); ZZ_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) DivRem21(qbuf, buf, buf, F); else div21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F) { long da, db, d, n, k; da = deg(a); db = deg(b); n = F.n; if (n < 0) LogicError("MulMod: uninitialized modulus"); if (da >= n || db >= n) LogicError("bad args to MulMod(ZZ_pX,ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (da < 0 || db < 0) { clear(x); return; } if (!F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER || db <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; mul(P1, a, b); rem(x, P1, F); return; } d = da + db + 1; k = NextPowerOfTwo(d); k = max(k, F.k); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep_trunc(R1, a, k, max(1L << F.k, d)); ToFFTRep_trunc(R2, b, k, max(1L << F.k, d)); mul(R1, R1, R2); NDFromFFTRep(P1, R1, n, d-1, R2); // save R1 for future use ToFFTRep_trunc(R2, P1, F.l, 2*n-3); mul(R2, R2, F.HRep); FromFFTRep(P1, R2, n-2, 2*n-4); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long da, d, n, k; da = deg(a); n = F.n; if (n < 0) LogicError("SqrMod: uninitailized modulus"); if (da >= n) LogicError("bad args to SqrMod(ZZ_pX,ZZ_pX,ZZ_pXModulus)"); if (!F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; sqr(P1, a); rem(x, P1, F); return; } d = 2*da + 1; k = NextPowerOfTwo(d); k = max(k, F.k); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep_trunc(R1, a, k, max(1L << F.k, d)); mul(R1, R1, R1); NDFromFFTRep(P1, R1, n, d-1, R2); // save R1 for future use ToFFTRep_trunc(R2, P1, F.l, 2*n-3); mul(R2, R2, F.HRep); FromFFTRep(P1, R2, n-2, 2*n-4); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void PlainInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) /* x = (1/a) % X^m, input not output, constant term a is nonzero */ { long i, k, n, lb; NTL_ZZRegister(v); NTL_ZZRegister(t); ZZ_p s; const ZZ_p* ap; ZZ_p* xp; n = deg(a); if (n < 0) ArithmeticError("division by zero"); inv(s, ConstTerm(a)); if (n == 0) { conv(x, s); return; } ap = a.rep.elts(); x.rep.SetLength(m); xp = x.rep.elts(); xp[0] = s; long is_one = IsOne(s); for (k = 1; k < m; k++) { clear(v); lb = max(k-n, 0); for (i = lb; i <= k-1; i++) { mul(t, rep(xp[i]), rep(ap[k-i])); add(v, v, t); } conv(xp[k], v); negate(xp[k], xp[k]); if (!is_one) mul(xp[k], xp[k], s); } x.normalize(); } void trunc(ZZ_pX& x, const ZZ_pX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; ZZ_p* xp; const ZZ_p* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void CyclicReduce(ZZ_pX& x, const ZZ_pX& a, long m) // computes x = a mod X^m-1 { long n = deg(a); long i, j; ZZ_p accum; if (n < m) { x = a; return; } if (&x != &a) x.rep.SetLength(m); for (i = 0; i < m; i++) { accum = a.rep[i]; for (j = i + m; j <= n; j += m) add(accum, accum, a.rep[j]); x.rep[i] = accum; } if (&x == &a) x.rep.SetLength(m); x.normalize(); } void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) { if (m < 0) LogicError("InvTrunc: bad args"); if (m == 0) { clear(x); return; } if (NTL_OVERFLOW(m, 1, 0)) ResourceError("overflow in InvTrunc"); if (&x == &a) { ZZ_pX la; la = a; if (m > NTL_ZZ_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, la, m); else PlainInvTrunc(x, la, m); } else { if (m > NTL_ZZ_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, a, m); else PlainInvTrunc(x, a, m); } } void build(ZZ_pXModulus& x, const ZZ_pX& f) { x.f = f; x.n = deg(f); x.tracevec.make(); if (x.n <= 0) LogicError("build: deg(f) must be at least 1"); if (x.n <= NTL_ZZ_pX_FFT_CROSSOVER + 1) { x.UseFFT = 0; return; } x.UseFFT = 1; x.k = NextPowerOfTwo(x.n); x.l = NextPowerOfTwo(2*x.n - 3); ToFFTRep(x.FRep, f, x.k); ZZ_pX P1(INIT_SIZE, x.n+1), P2(INIT_SIZE, x.n); CopyReverse(P1, f, 0, x.n); InvTrunc(P2, P1, x.n-1); CopyReverse(P1, P2, 0, x.n-2); ToFFTRep(x.HRep, P1, x.l); } ZZ_pXModulus::ZZ_pXModulus(const ZZ_pX& ff) { build(*this, ff); } ZZ_pXMultiplier::ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F) { build(*this, b, F); } void build(ZZ_pXMultiplier& x, const ZZ_pX& b, const ZZ_pXModulus& F) { long db; long n = F.n; if (n < 0) LogicError("build ZZ_pXMultiplier: uninitialized modulus"); x.b = b; db = deg(b); if (db >= n) LogicError("build ZZ_pXMultiplier: deg(b) >= deg(f)"); if (!F.UseFFT || db <= NTL_ZZ_pX_FFT_CROSSOVER) { x.UseFFT = 0; return; } x.UseFFT = 1; FFTRep R1(INIT_SIZE, F.l); ZZ_pX P1(INIT_SIZE, n); ToFFTRep_trunc(R1, b, F.l, 2*n-2); reduce(x.B2, R1, F.k); mul(R1, R1, F.HRep); FromFFTRep(P1, R1, n-1, 2*n-3); ToFFTRep(x.B1, P1, F.l); // could be truncated to length max(1L << F.k, 2*n-2), except // for the usage in UpdateMap, where we would have to investigate // further } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { long n = F.n; long da; da = deg(a); if (da >= n) LogicError(" bad args to MulMod(ZZ_pX,ZZ_pX,ZZ_pXMultiplier,ZZ_pXModulus)"); if (da < 0) { clear(x); return; } if (!B.UseFFT || !F.UseFFT || da <= NTL_ZZ_pX_FFT_CROSSOVER) { ZZ_pX P1; mul(P1, a, B.b); rem(x, P1, F); return; } ZZ_pX P1(INIT_SIZE, n), P2(INIT_SIZE, n); FFTRep R1(INIT_SIZE, F.l), R2(INIT_SIZE, F.l); ToFFTRep_trunc(R1, a, F.l, max(1L << F.k, 2*n-2)); mul(R2, R1, B.B1); FromFFTRep(P1, R2, n-1, 2*n-3); reduce(R1, R1, F.k); mul(R1, R1, B.B2); ToFFTRep(R2, P1, F.k); mul(R2, R2, F.FRep); sub(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void PowerXMod(ZZ_pX& hh, const ZZ& e, const ZZ_pXModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; ZZ_pX h, h1; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { if (bit(e, i)) { SqrMod(h1, h, F); MulByXMod(h, h1, F); // NOTE: MulByXMod gives much faster multicore performance // when output does not alias input } else SqrMod(h, h, F); } if (e < 0) InvMod(h, h, F); hh = h; } void PowerXPlusAMod(ZZ_pX& hh, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F) { if (F.n < 0) LogicError("PowerXPlusAMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } ZZ_pX t1(INIT_SIZE, F.n), t2(INIT_SIZE, F.n); long n = NumBits(e); long i; ZZ_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(t1, h, F); mul(t2, h, a); add(h, t1, t2); } } if (e < 0) InvMod(h, h, F); hh = h; } void PowerMod(ZZ_pX& h, const ZZ_pX& g, const ZZ& e, const ZZ_pXModulus& F) { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (IsZero(e)) { set(h); return; } ZZ_pXMultiplier G; ZZ_pX res; long n = NumBits(e); long i; build(G, g, F); res.SetMaxLength(F.n); set(res); for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, G, F); } if (e < 0) InvMod(res, res, F); h = res; } void NewtonInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m) { x.SetMaxLength(m); long i, t, k; long log2_newton = NextPowerOfTwo(NTL_ZZ_pX_NEWTON_CROSSOVER)-1; PlainInvTrunc(x, a, 1L << log2_newton); t = NextPowerOfTwo(m); FFTRep R1(INIT_SIZE, t), R2(INIT_SIZE, t); ZZ_pX P1(INIT_SIZE, m/2); long a_len = min(m, a.rep.length()); ZZ_pXModRep a_rep; ToZZ_pXModRep(a_rep, a, 0, a_len-1); k = 1L << log2_newton; t = log2_newton; while (k < m) { long l = min(2*k, m); ToFFTRep(R1, x, t+1); ToFFTRep(R2, a_rep, t+1, 0, l-1); mul(R2, R2, R1); FromFFTRep(P1, R2, k, l-1); ToFFTRep(R2, P1, t+1); mul(R2, R2, R1); FromFFTRep(P1, R2, 0, l-k-1); x.rep.SetLength(l); long y_len = P1.rep.length(); for (i = k; i < l; i++) { if (i-k >= y_len) clear(x.rep[i]); else negate(x.rep[i], P1.rep[i-k]); } x.normalize(); t++; k = l; } } void FFTDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { clear(q); r = a; return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); DivRem(q, r, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k1, k); FFTRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; ToFFTRep(R1, b, k1); ToFFTRep(R2, P3, k1); mul(R1, R1, R2); FromFFTRep(P1, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P1); q = P3; } void FFTDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k; if (m < n) { clear(q); return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); div(q, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(q, R1, m-n, 2*(m-n)); } void FFTRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { r = a; return; } if (m >= 3*n) { ZZ_pXModulus B; build(B, b); rem(r, a, B); return; } ZZ_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k, k1); FFTRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); ToFFTRep(R1, P1, k); ToFFTRep(R2, a, k, n, m); mul(R1, R1, R2); FromFFTRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; ToFFTRep(R1, b, k1); ToFFTRep(R2, P3, k1); mul(R1, R1, R2); FromFFTRep(P3, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P3); } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTDivRem(q, r, a, b); else PlainDivRem(q, r, a, b); } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTDiv(q, a, b); else PlainDiv(q, a, b); } void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b) { NTL_ZZ_pRegister(T); inv(T, b); mul(q, a, T); } void div(ZZ_pX& q, const ZZ_pX& a, long b) { NTL_ZZ_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b) { if (deg(b) > NTL_ZZ_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_ZZ_pX_DIV_CROSSOVER) FFTRem(r, a, b); else PlainRem(r, a, b); } long operator==(const ZZ_pX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_ZZ_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const ZZ_pX& a, const ZZ_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void power(ZZ_pX& x, const ZZ_pX& a, long e) { if (e < 0) { LogicError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); ZZ_pX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(ZZ_pX& x, const ZZ_pX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { ZZ_pX tmp; CopyReverse(tmp, a, 0, hi); x = tmp; } else CopyReverse(x, a, 0, hi); } NTL_END_IMPL ntl-11.5.1/src/ZZ_pX1.cpp0000644417616742025610000011741514064716022016554 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } ZZ_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const ZZ_pX& a, const ZZ_pX& b) { if (IsZero(b)) return IsZero(a); ZZ_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } void ZZ_pXMatrix::operator=(const ZZ_pXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } void RightShift(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(ZZ_pX& U, const ZZ_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void ShiftSub(ZZ_pX& U, const ZZ_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void mul(ZZ_pX& U, ZZ_pX& V, const ZZ_pXMatrix& M) // (U, V)^T = M*(U, V)^T { long d = deg(U) - deg(M(1,1)); long k = NextPowerOfTwo(d - 1); // When the GCD algorithm is run on polynomials of degree n, n-1, // where n is a power of two, then d-1 is likely to be a power of two. // It would be more natural to set k = NextPowerOfTwo(d+1), but this // would be much less efficient in this case. // We optimize this case, as it does sometimes arise naturally // in some situations. long n = (1L << k); long xx; ZZ_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0; NTL_ZZRegister(t1); NTL_ZZRegister(t2); if (n == d-1) xx = 1; else if (n == d) xx = 2; else xx = 3; switch (xx) { case 1: GetCoeff(a0, M(0,0), 0); GetCoeff(a1, M(0,0), 1); GetCoeff(b0, M(0,1), 0); GetCoeff(b1, M(0,1), 1); GetCoeff(c0, M(1,0), 0); GetCoeff(d0, M(1,1), 0); GetCoeff(u0, U, 0); GetCoeff(u1, U, 1); GetCoeff(v0, V, 0); GetCoeff(v1, V, 1); mul(t1, rep(a0), rep(u0)); mul(t2, rep(b0), rep(v0)); add(t1, t1, t2); conv(nu0, t1); mul(t1, rep(a1), rep(u0)); mul(t2, rep(a0), rep(u1)); add(t1, t1, t2); mul(t2, rep(b1), rep(v0)); add(t1, t1, t2); mul(t2, rep(b0), rep(v1)); add(t1, t1, t2); conv(nu1, t1); mul(t1, rep(c0), rep(u0)); mul(t2, rep(d0), rep(v0)); add (t1, t1, t2); conv(nv0, t1); break; case 2: GetCoeff(a0, M(0,0), 0); GetCoeff(b0, M(0,1), 0); GetCoeff(u0, U, 0); GetCoeff(v0, V, 0); mul(t1, rep(a0), rep(u0)); mul(t2, rep(b0), rep(v0)); add(t1, t1, t2); conv(nu0, t1); break; case 3: break; } FFTRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(RU, U, k); ToFFTRep(RV, V, k); ToFFTRep(R1, M(0,0), k); mul(R1, R1, RU); ToFFTRep(R2, M(0,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromFFTRep(U, R1, 0, d); ToFFTRep(R1, M(1,0), k); mul(R1, R1, RU); ToFFTRep(R2, M(1,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromFFTRep(V, R1, 0, d-1); // now fix-up results switch (xx) { case 1: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d-1, u0); SetCoeff(U, 0, nu0); GetCoeff(u1, U, 1); sub(u1, u1, nu1); SetCoeff(U, d, u1); SetCoeff(U, 1, nu1); GetCoeff(v0, V, 0); sub(v0, v0, nv0); SetCoeff(V, d-1, v0); SetCoeff(V, 0, nv0); break; case 2: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d, u0); SetCoeff(U, 0, nu0); break; } } void mul(ZZ_pXMatrix& A, ZZ_pXMatrix& B, ZZ_pXMatrix& C) // A = B*C, B and C are destroyed { long db = deg(B(1,1)); long dc = deg(C(1,1)); long da = db + dc; long k = NextPowerOfTwo(da+1); FFTRep B00, B01, B10, B11, C0, C1, T1, T2; ToFFTRep(B00, B(0,0), k); B(0,0).kill(); ToFFTRep(B01, B(0,1), k); B(0,1).kill(); ToFFTRep(B10, B(1,0), k); B(1,0).kill(); ToFFTRep(B11, B(1,1), k); B(1,1).kill(); ToFFTRep(C0, C(0,0), k); C(0,0).kill(); ToFFTRep(C1, C(1,0), k); C(1,0).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromFFTRep(A(0,0), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromFFTRep(A(1,0), T1, 0, da); ToFFTRep(C0, C(0,1), k); C(0,1).kill(); ToFFTRep(C1, C(1,1), k); C(1,1).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromFFTRep(A(0,1), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromFFTRep(A(1,1), T1, 0, da); } void IterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; ZZVec tmp(deg(U)+1, ZZ_p::ExtendedModulusSize()); ZZ_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V, tmp); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void HalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; ZZ_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(ZZ_pX& U, ZZ_pX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); ZZ_pX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(ZZ_pX& d, const ZZ_pX& u, const ZZ_pX& v) { ZZ_pX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } ZZ_pX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } ZZ_pXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(ZZ_p* a, long n) { long i, k; ZZ_p b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void mul(ZZ_p* x, const ZZ_p* a, const ZZ_p* b, long n) { NTL_ZZRegister(t); NTL_ZZRegister(accum); long i, j, jmin, jmax; long d = 2*n-1; for (i = 0; i <= d; i++) { jmin = max(0, i-(n-1)); jmax = min(n-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(a[j]), rep(b[i-j])); add(accum, accum, t); } if (i >= n) { add(accum, accum, rep(a[i-n])); add(accum, accum, rep(b[i-n])); } conv(x[i], accum); } } void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a) { long n = a.length(); if (n == 0) { set(x); return; } long k0 = NextPowerOfTwo(NTL_ZZ_pX_FFT_CROSSOVER); long crossover = 1L << k0; if (n <= crossover) { x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); return; } long k = NextPowerOfTwo(n); long m = 1L << k; long i, j; long l, width; ZZ_pX b(INIT_SIZE, m+1); b.rep = a; b.rep.SetLength(m+1); for (i = n; i < m; i++) clear(b.rep[i]); set(b.rep[m]); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ZZ_p t1, one; set(one); vec_ZZ_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover); ZZ_p *g = G.elts(); ZZ_p *h = H.elts(); ZZ_p *tmp; for (i = 0; i < m; i+= crossover) { for (j = 0; j < crossover; j++) negate(g[j], b.rep[i+j]); if (k0 > 0) { for (j = 0; j < crossover; j+=2) { mul(t1, g[j], g[j+1]); add(g[j+1], g[j], g[j+1]); g[j] = t1; } } for (l = 1; l < k0; l++) { width = 1L << l; for (j = 0; j < crossover; j += 2*width) mul(&h[j], &g[j], &g[j+width], width); tmp = g; g = h; h = tmp; } for (j = 0; j < crossover; j++) b.rep[i+j] = g[j]; } for (l = k0; l < k; l++) { width = 1L << l; for (i = 0; i < m; i += 2*width) { t1 = b.rep[i+width]; set(b.rep[i+width]); ToFFTRep(R1, b, l+1, i, i+width); b.rep[i+width] = t1; t1 = b.rep[i+2*width]; set(b.rep[i+2*width]); ToFFTRep(R2, b, l+1, i+width, i+2*width); b.rep[i+2*width] = t1; mul(R1, R1, R2); FromFFTRep(&b.rep[i], R1, 0, 2*width-1); sub(b.rep[i], b.rep[i], one); } } x.rep.SetLength(n+1); long delta = m-n; for (i = 0; i <= n; i++) x.rep[i] = b.rep[i+delta]; // no need to normalize } void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a) // does a Horner evaluation { ZZ_p acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_ZZ_p bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b) { long m = a.length(); if (b.length() != m) LogicError("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_ZZ_p prod; prod = a; ZZ_p t1, t2; long k, i; vec_ZZ_p res; res.SetLength(m); for (k = 0; k < m; k++) { const ZZ_p& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } NTL_TBDECL(InnerProduct)(ZZ_pX& x, const vec_ZZ_p& v, long low, long high, const vec_ZZ_pX& H, long n, ZZVec& t) { NTL_ZZRegister(s); long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_ZZ_p& h = H[i-low].rep; long m = h.length(); const ZZ& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } #ifdef NTL_THREAD_BOOST void InnerProduct(ZZ_pX& x, const vec_ZZ_p& v, long low, long high, const vec_ZZ_pX& H, long n, ZZVec& t) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1) { basic_InnerProduct(x, v, low, high, H, n, t); return; } high = min(high, v.length()-1); x.rep.SetLength(n); ZZ_pContext local_context; local_context.save(); pool->exec_range(n, [low, high, &x, &t, &H, &v, &local_context](long first, long last) { local_context.restore(); NTL_ZZRegister(s); for (long j = first; j < last; j++) clear(t[j]); for (long i = low; i <= high; i++) { const vec_ZZ_p& h = H[i-low].rep; long m = min(h.length(), last); const ZZ& w = rep(v[i]); for (long j = first; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } for (long j = first; j < last; j++) conv(x.rep[j], t[j]); } ); x.normalize(); } #endif void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& A, const ZZ_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } ZZ_pX s, t; ZZVec scratch(F.n, ZZ_p::ExtendedModulusSize()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; ZZ_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(ZZ_pXArgument& A, const ZZ_pX& h, const ZZ_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) LogicError("build: bad args"); if (m > F.n) m = F.n; long i; if (ZZ_pXArgBound > 0) { double sz = ZZ_p::storage(); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz/1024; m = min(m, long(ZZ_pXArgBound/sz)); m = max(m, 1); } ZZ_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); } NTL_CHEAP_THREAD_LOCAL long ZZ_pXArgBound = 0; void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } ZZ_pXNewArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } ZZ_pXNewArgument A; build(A, h, F, m); ZZ_pX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } ZZ_pXNewArgument A; build(A, h, F, m); ZZ_pX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } static void StripZeroes(vec_ZZ_p& x) { long n = x.length(); while (n > 0 && IsZero(x[n-1])) n--; x.SetLength(n); } void PlainUpdateMap(vec_ZZ_p& xx, const vec_ZZ_p& a, const ZZ_pX& b, const ZZ_pX& f) { long n = deg(f); long i, m; if (IsZero(b)) { xx.SetLength(0); return; } m = n-1 - deg(b); vec_ZZ_p x(INIT_SIZE, n); for (i = 0; i <= m; i++) InnerProduct(x[i], a, b.rep, i); if (deg(b) != 0) { ZZ_pX c(INIT_SIZE, n); LeftShift(c, b, m); for (i = m+1; i < n; i++) { MulByXMod(c, c, f); InnerProduct(x[i], a, c.rep); } } xx = x; } void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& aa, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { long n = F.n; long i; vec_ZZ_p a; a = aa; StripZeroes(a); if (a.length() > n) LogicError("UpdateMap: bad args"); if (!B.UseFFT) { PlainUpdateMap(x, a, B.b, F.f); StripZeroes(x); return; } FFTRep R1(INIT_SIZE, F.k), R2(INIT_SIZE, F.l); vec_ZZ_p V1(INIT_SIZE, n); RevToFFTRep(R1, a, F.k, 0, a.length()-1, 0); mul(R2, R1, F.FRep); RevFromFFTRep(V1, R2, 0, n-2); for (i = 0; i <= n-2; i++) negate(V1[i], V1[i]); RevToFFTRep(R2, V1, F.l, 0, n-2, n-1); mul(R2, R2, B.B1); mul(R1, R1, B.B2); AddExpand(R2, R1); RevFromFFTRep(x, R2, 0, n-1); StripZeroes(x); } NTL_TBDECL(ProjectPowers)(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pXMultiplier M; build(M, H.H[m], F); vec_ZZ_p s(INIT_SIZE, n); s = a; StripZeroes(s); x.SetLength(k); for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); ZZ_p* w = &x[i*m]; for (long j = 0; j < m1; j++) InnerProduct(w[j], H.H[j].rep, s); if (i < l) UpdateMap(s, s, M, F); } } #ifdef NTL_THREAD_BOOST void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active() || pool->NumThreads() == 1) { basic_ProjectPowers(x, a, k, H, F); return; } long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; ZZ_pXMultiplier M; build(M, H.H[m], F); vec_ZZ_p s(INIT_SIZE, n); s = a; StripZeroes(s); x.SetLength(k); ZZ_pContext local_context; local_context.save(); for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); ZZ_p* w = &x[i*m]; pool->exec_range(m1, [w, &H, &s, &local_context](long first, long last) { local_context.restore(); for (long j = first; j < last; j++) InnerProduct(w[j], H.H[j].rep, s); } ); if (i < l) UpdateMap(s, s, M, F); } } #endif void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F) { if (a.length() > F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); ZZ_pXNewArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } #ifdef NTL_USE_ZZ_pXNewArgument // ZZ_pXNewArgument stuff void build(ZZ_pXNewArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m) { long n = F.n; if (m <= 0 || deg(h) >= n) LogicError("build: bad args"); if (NTL_OVERFLOW(m, 1, 0)) ResourceError("ZZ_pXNewArgument:build: m too big"); // NOTE: we don't take ZZ_pXArgBound into account, as the // new strategy anyway always uses space about (m + deg(g)/m)*n long width; // usually n, but may be smaller if h has very low degree // some messiness here to avoid overflow long dh = deg(h); if (dh < 0) width = 1; else if (dh == 0 || m-1 == 0) width = 1; else if (dh <= n/(m-1)) width = min(n, dh*(m-1) + 1); else width = n; ZZ_pXMultiplier M; build(M, h, F); Mat mat; mat.SetDims(m, width); ZZ_pX poly; poly = 1; for (long i = 0; i < m; i++) { VectorCopy(mat[i], poly, width); MulMod(poly, poly, M, F); } H.mat.move(mat); H.poly.swap(poly); } void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F) { long d = deg(g)+1; if (d <= 1) { x = g; return; } long m = H.mat.NumRows(); if (m == 0) LogicError("CompMod: uninitialized argument"); long l = (d+m-1)/m; Mat gmat; gmat.SetDims(l, m); for (long i = 0; i < l; i++) for (long j = 0; j < m; j++) gmat[i][j] = coeff(g, i*m+j); Mat xmat; mul(xmat, gmat, H.mat); ZZ_pX t; conv(t, xmat[l-1]); if (l-2 >= 0) { ZZ_pXMultiplier M; build(M, H.poly, F); ZZ_pX s; for (long i = l-2; i >= 0; i--) { conv(s, xmat[i]); MulMod(t, t, M, F); add(t, t, s); } } x = t; } void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.mat.NumRows(); if (m == 0) LogicError("CompMod: uninitialized argument"); long width = H.mat.NumCols(); long l = (k+m-1)/m; Mat amat, xmat; amat.SetDims(l, width); vec_ZZ_p s(INIT_SIZE, n); s = a; StripZeroes(s); VectorCopy(amat[0], s, width); if (l > 1) { ZZ_pXMultiplier M; build(M, H.poly, F); for (long i = 1; i < l; i++) { UpdateMap(s, s, M, F); VectorCopy(amat[i], s, width); } } mul_transpose(xmat, amat, H.mat); x.SetLength(k); for (long i = 0; i < l; i++) { long j_max = min(m, k-i*m); for (long j = 0; j < j_max; j++) x[i*m+j] = xmat[i][j]; } } #endif void BerlekampMassey(ZZ_pX& h, const vec_ZZ_p& a, long m) { ZZ_pX Lambda, Sigma, Temp; long L; ZZ_p Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void GCDMinPolySeq(ZZ_pX& h, const vec_ZZ_p& x, long m) { long i; ZZ_pX a, b; ZZ_pXMatrix M; ZZ_p t; a.rep.SetLength(2*m); for (i = 0; i < 2*m; i++) a.rep[i] = x[2*m-1-i]; a.normalize(); SetCoeff(b, 2*m); HalfGCD(M, b, a, m+1); /* make monic */ inv(t, LeadCoeff(M(1,1))); mul(h, M(1,1), t); } void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m) { if (m < 0) LogicError("MinPoly: bad args"); if (NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); if (m > NTL_ZZ_pX_BERMASS_CROSSOVER) GCDMinPolySeq(h, a, m); else BerlekampMassey(h, a, m); } void DoMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m, const vec_ZZ_p& R) { vec_ZZ_p x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); long i; vec_ZZ_p R(INIT_SIZE, n); for (i = 0; i < n; i++) random(R[i]); DoMinPolyMod(h, g, F, m, R); } void MinPolyMod(ZZ_pX& hh, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; ZZ_pX h2, h3; ZZ_pXMultiplier H1; vec_ZZ_p R(INIT_SIZE, n); for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, H1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) { vec_ZZ_p R(INIT_SIZE, 1); if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); set(R[0]); DoMinPolyMod(h, g, F, m, R); } void diff(ZZ_pX& x, const ZZ_pX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(ZZ_pX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; ZZ_p t; inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { ZZ_pX y; mul(y, a, b); trunc(x, y, n); } void FFTMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long d = deg(a) + deg(b); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); ToFFTRep(R1, a, k); ToFFTRep(R2, b, k); mul(R1, R1, R2); FromFFTRep(x, R1, 0, n-1); } void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n) { if (n < 0) LogicError("MulTrunc: bad args"); if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER || deg(b) <= NTL_ZZ_pX_FFT_CROSSOVER) PlainMulTrunc(x, a, b, n); else FFTMulTrunc(x, a, b, n); } void PlainSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { ZZ_pX y; sqr(y, a); trunc(x, y, n); } void FFTSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { if (IsZero(a)) { clear(x); return; } long d = 2*deg(a); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); FFTRep R1(INIT_SIZE, k); ToFFTRep(R1, a, k); mul(R1, R1, R1); FromFFTRep(x, R1, 0, n-1); } void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n) { if (n < 0) LogicError("SqrTrunc: bad args"); if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER) PlainSqrTrunc(x, a, n); else FFTSqrTrunc(x, a, n); } void FastTraceVec(vec_ZZ_p& S, const ZZ_pX& f) { long n = deg(f); if (n <= 0) LogicError("FastTraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } if (n == 1) { S.SetLength(1); set(S[0]); return; } long i; ZZ_pX f1; f1.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) f1.rep[i] = f.rep[n-i]; f1.normalize(); ZZ_pX f2; f2.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) mul(f2.rep[i], f.rep[n-1-i], i+1); f2.normalize(); ZZ_pX f3; InvTrunc(f3, f1, n-1); MulTrunc(f3, f3, f2, n-1); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(f3, i-1)); } void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); ZZ_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ acc, t; ZZ_p t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_ZZ_p& S, const ZZ_pX& f) { if (deg(f) <= NTL_ZZ_pX_TRACE_CROSSOVER) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(vec_ZZ_p& S, const ZZ_pXModulus& F) { if (!F.UseFFT) { PlainTraceVec(S, F.f); return; } long i; long n = F.n; FFTRep R; ZZ_pX P, g; g.rep.SetLength(n-1); for (i = 1; i < n; i++) mul(g.rep[n-i-1], F.f.rep[n-i], i); g.normalize(); ToFFTRep(R, g, F.l); mul(R, R, F.HRep); FromFFTRep(P, R, n-2, 2*n-4); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(P, n-1-i)); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); InnerProduct(x, a.rep, *F.tracevec.val()); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(ZZ_p& rres, const ZZ_pX& a, const ZZ_pX& b) { ZZ_p res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; ZZ_p lc; set(res); long n = max(deg(a),deg(b)) + 1; ZZ_pX u(INIT_SIZE, n), v(INIT_SIZE, n); ZZVec tmp(n, ZZ_p::ExtendedModulusSize()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void ResIterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red, vec_ZZ_p& cvec, vec_long& dvec) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; ZZVec tmp(deg(U)+1, ZZ_p::ExtendedModulusSize()); ZZ_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); PlainDivRem(Q, U, U, V, tmp); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void ResHalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red, vec_ZZ_p& cvec, vec_long& dvec) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; ZZ_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; ResHalfGCD(M1, U1, V1, d1, cvec, dvec); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } ZZ_pX Q; ZZ_pXMatrix M2; append(cvec, LeadCoeff(V1)); append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1)); DivRem(Q, U1, U1, V1); swap(U1, V1); ResHalfGCD(M2, U1, V1, d2, cvec, dvec); ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void ResHalfGCD(ZZ_pX& U, ZZ_pX& V, vec_ZZ_p& cvec, vec_long& dvec) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; ZZ_pXMatrix M1; ResHalfGCD(M1, U, V, d1, cvec, dvec); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); ZZ_pX Q; append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); DivRem(Q, U, U, V); swap(U, V); ResHalfGCD(M1, U, V, d2, cvec, dvec); mul(U, V, M1); } void resultant(ZZ_p& rres, const ZZ_pX& u, const ZZ_pX& v) { if (deg(u) <= NTL_ZZ_pX_GCD_CROSSOVER || deg(v) <= NTL_ZZ_pX_GCD_CROSSOVER) { PlainResultant(rres, u, v); return; } ZZ_pX u1, v1; u1 = u; v1 = v; ZZ_p res, t; set(res); if (deg(u1) == deg(v1)) { rem(u1, u1, v1); swap(u1, v1); if (IsZero(v1)) { clear(rres); return; } power(t, LeadCoeff(u1), deg(u1) - deg(v1)); mul(res, res, t); if (deg(u1) & 1) negate(res, res); } else if (deg(u1) < deg(v1)) { swap(u1, v1); if (deg(u1) & deg(v1) & 1) negate(res, res); } // deg(u1) > deg(v1) && v1 != 0 vec_ZZ_p cvec; vec_long dvec; cvec.SetMaxLength(deg(v1)+2); dvec.SetMaxLength(deg(v1)+2); append(cvec, LeadCoeff(u1)); append(dvec, deg(u1)); while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) { ResHalfGCD(u1, v1, cvec, dvec); if (!IsZero(v1)) { append(cvec, LeadCoeff(v1)); append(dvec, deg(v1)); rem(u1, u1, v1); swap(u1, v1); } } if (IsZero(v1) && deg(u1) > 0) { clear(rres); return; } long i, l; l = dvec.length(); if (deg(u1) == 0) { // we went all the way... for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]); mul(res, res, t); } else { for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]-deg(v1)); mul(res, res, t); if (dvec[l-2] & dvec[l-1] & 1) negate(res, res); PlainResultant(t, u1, v1); mul(res, res, t); } rres = res; } void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } ZZ_p t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { ZZ_p t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } NTL_END_IMPL ntl-11.5.1/src/ZZ_pXCharPoly.cpp0000644417616742025610000000223314064716022020124 0ustar gid-shoupvpug-gid-shoupv#include NTL_START_IMPL static void HessCharPoly(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f) { long n = deg(f); if (n <= 0 || deg(a) >= n) LogicError("HessCharPoly: bad args"); mat_ZZ_p M; M.SetDims(n, n); long i, j; ZZ_pX t; t = a; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = coeff(t, j); if (i < n-1) MulByXMod(t, t, f); } CharPoly(g, M); } void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& ff) { ZZ_pX f = ff; MakeMonic(f); long n = deg(f); if (n <= 0 || deg(a) >= n) LogicError("CharPoly: bad args"); if (IsZero(a)) { clear(g); SetCoeff(g, n); return; } if (n > 25) { ZZ_pX h; MinPolyMod(h, a, f); if (deg(h) == n) { g = h; return; } } if (ZZ_p::modulus() < n+1) { HessCharPoly(g, a, f); return; } vec_ZZ_p u(INIT_SIZE, n+1), v(INIT_SIZE, n+1); ZZ_pX h, h1; negate(h, a); long i; for (i = 0; i <= n; i++) { u[i] = i; add(h1, h, u[i]); resultant(v[i], f, h1); } interpolate(g, u, v); } NTL_END_IMPL ntl-11.5.1/src/ZZ_pXFactoring.cpp0000644417616742025610000010246614064716022020330 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_START_IMPL void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SquareFreeDecomp: bad args"); ZZ_pX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; conv(p, ZZ_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) f.rep[k] = r.rep[k*p]; m = m*p; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_ZZVec& M, long verbose) { long k, l, n; long i, j; long pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p, and make row l reduced InvMod(t1, M[l][k], p); NegateMod(t1, t1, p); for (j = k+1; j < n; j++) { rem(t2, M[l][j], p); MulMod(M[l][j], t2, t1, p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(vec_ZZVec& M, long n, const ZZ_pX& g, const ZZ_pXModulus& F, long verbose) { long i, j, m; ZZ_pXMultiplier G; ZZ_pX h; ZZ t; sqr(t, ZZ_p::modulus()); mul(t, t, n); long size = t.size(); M.SetLength(n); for (i = 0; i < n; i++) M[i].SetSize(n, size); build(G, g, F); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = rep(h.rep[i]); else clear(M[i][j]); } if (j < n-1) MulMod(h, h, G, F); } for (i = 0; i < n; i++) AddMod(M[i][i], M[i][i], -1, ZZ_p::modulus()); } static void RecFindRoots(vec_ZZ_p& x, const ZZ_pX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pX h; ZZ_p r; ZZ p1; RightShift(p1, ZZ_p::modulus(), 1); { ZZ_pXModulus F; build(F, f); do { random(r); PowerXPlusAMod(h, r, p1, F); add(h, h, -1); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_ZZ_p& x, const ZZ_pX& ff) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(ZZ_pX& g, const vec_long& D, const vec_ZZVec& M) { ZZ t1, t2; long n = D.length(); long i, j, s; g.rep.SetLength(n); vec_ZZ_p& v = g.rep; for (j = n-1; j >= 0; j--) { if (D[j] == -1) random(v[j]); else { i = D[j]; // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s] clear(t1); for (s = j+1; s < n; s++) { mul(t2, rep(v[s]), M[i][s]); add(t1, t1, t2); } conv(v[j], t1); } } g.normalize(); } static void split(ZZ_pX& f1, ZZ_pX& g1, ZZ_pX& f2, ZZ_pX& g2, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots, long lo, long mid) { long r = mid-lo+1; ZZ_pXModulus F; build(F, f); vec_ZZ_p lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; ZZ_pX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } ZZ_pX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g, const vec_ZZ_p& roots) { long r = roots.length(); long i; ZZ_pX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; const ZZ& p = ZZ_p::modulus(); long n = deg(f); ZZ_pXModulus F; build(F, f); ZZ_pX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(g, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_long D; long r; vec_ZZVec M; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } NullSpace(r, D, M, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_ZZ_p roots; RandomBasisElt(g, D, M); MinPolyMod(h, g, F, r); if (deg(h) == r) M.kill(); FindRoots(roots, h); FindFactors(factors, f, g, roots); ZZ_pX g1; vec_ZZ_pX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, D, M); S.kill(); for (i = 0; i < factors.length(); i++) { const ZZ_pX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose) { double t; vec_pair_ZZ_pX_long sfd; vec_ZZ_pX x; if (!IsOne(LeadCoeff(f))) LogicError("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_ZZ_pX_long& factors, const ZZ_pX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(ZZ_pX& f, vec_pair_ZZ_pX_long& factors, const ZZ_pXModulus& F, long limit, const vec_ZZ_pX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; ZZ_pX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); ZZ_pX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b) { if (d < 0) LogicError("TraceMap: bad args"); ZZ_pX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(ZZ_pX& y, const ZZ_pX& h, long q, const ZZ_pXModulus& F) { if (q < 0) LogicError("PowerCompose: bad args"); ZZ_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const ZZ_pX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; const ZZ& p = ZZ_p::modulus(); ZZ_pXModulus F; build(F, f); ZZ_pX b, r, s; PowerXMod(b, p, F); long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); if (deg(s) > 0) return 0; } if (p >= n) return 1; long pp; conv(pp, p); if (n % pp != 0) return 1; PowerCompose(s, b, n/pp, F); return !IsX(s); } NTL_CHEAP_THREAD_LOCAL long ZZ_pX_BlockingFactor = 10; void DDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff, const ZZ_pX& hh, long verbose) { ZZ_pX f = ff; ZZ_pX h = hh; if (!IsOne(LeadCoeff(f))) LogicError("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = ZZ_pX_BlockingFactor; ZZ_pXModulus F; build(F, f); ZZ_pXNewArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; ZZ_pX g, X; vec_ZZ_pX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); sub(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose) { vec_ZZ_p roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_ZZ_pX& v, const ZZ_pX& f, const ZZ_pX& b, long d) { ZZ_pX a, g, h; ZZ_pXModulus F; vec_ZZ_p roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& b, long d, long verbose) { vec_ZZ_pX v; long i; ZZ_pX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { ZZ_pX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_ZZ_pX& factors, const ZZ_pX& ff, const ZZ_pX& bb, long d, long verbose) { ZZ_pX f = ff; ZZ_pX b = bb; if (!IsOne(LeadCoeff(f))) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose) { ZZ_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; const ZZ& p = ZZ_p::modulus(); ZZ_pXModulus F; build(F, f); ZZ_pX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_ZZ_pX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } ZZ_pX hh; vec_ZZ_pX v; long i; for (i = 0; i < u.length(); i++) { const ZZ_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("CanZass: bad args"); double t; vec_pair_ZZ_pX_long sfd; vec_ZZ_pX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); ZZ_pX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F) { long b, e; ZZ_pX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } static void TandemPowerCompose(ZZ_pX& y1, ZZ_pX& y2, const ZZ_pX& h, long q1, long q2, const ZZ_pXModulus& F) { ZZ_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } static long RecComputeDegree(long u, const ZZ_pX& h, const ZZ_pXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); ZZ_pX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F) { if (F.n == 1 || IsX(h)) return 1; long n = F.n; ZZ_pX P1, P2, P3; random(P1, n); TraceMap(P2, P1, n, F, h); ProbMinPolyMod(P3, P2, F, n/2); long r = deg(P3); if (r <= 0 || n % r != 0) return 0; else return n/r; } void FindRoot(ZZ_p& root, const ZZ_pX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pXModulus F; ZZ_pX h, h1, f; ZZ_p r; ZZ p1; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); RightShift(p1, ZZ_p::modulus(), 1); h1 = 1; while (deg(f) > 1) { build(F, f); random(r); PowerXPlusAMod(h, r, p1, F); sub(h, h, h1); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F) { long e; ZZ_pX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const ZZ_pX& h, const ZZ_pXModulus& F, const FacVec& fvec) { long q1, q2; ZZ_pX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const ZZ_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pXModulus F; build(F, f); ZZ_pX h; PowerXMod(h, ZZ_p::modulus(), F); ZZ_pX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const ZZ_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; ZZ_pXModulus F; build(F, f); ZZ_pX h; PowerXMod(h, ZZ_p::modulus(), F); long CompTableSize = 2*SqrRoot(deg(f)); ZZ_pXNewArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; ZZ_pX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_ZZ_pX& h, const ZZ_pX& f, const ZZ_pX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { ZZ_pX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(ZZ_pX& x, const ZZ_pX& f, const ZZ_pX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_ZZ_pX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_ZZ_p a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(ZZ_pX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(ZZ_pX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { ZZ_pX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(ZZ_pX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g) { ZZ_pXModulus G; ZZ_pX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_CHEAP_THREAD_LOCAL long ZZ_pX_GCDTableSize = 4; NTL_CHEAP_THREAD_LOCAL double ZZ_pXFileThresh = NTL_FILE_THRESH; static NTL_CHEAP_THREAD_LOCAL vec_ZZ_pX *BabyStepFile = 0; static NTL_CHEAP_THREAD_LOCAL vec_ZZ_pX *GiantStepFile = 0; static NTL_CHEAP_THREAD_LOCAL long use_files; static double CalcTableSize(long n, long k) { double sz = ZZ_p::storage(); sz = sz * n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(ZZ_pX& h1, const ZZ_pX& f, const ZZ_pX& h, long k, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } ZZ_pXModulus F; build(F, f); ZZ_pXNewArgument H; build(H, h, F, 2*SqrRoot(F.n)); h1 = h; long i; if (!use_files) { (*BabyStepFile).SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("baby", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const ZZ_pX& f, const ZZ_pX& h, long l, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } ZZ_pXModulus F; build(F, f); ZZ_pXNewArgument H; build(H, h, F, 2*SqrRoot(F.n)); ZZ_pX h1; h1 = h; long i; if (!use_files) { (*GiantStepFile).SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void NewAddFactor(vec_pair_ZZ_pX_long& u, const ZZ_pX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_ZZ_pX_long& u, ZZ_pX& f, const ZZ_pXModulus& F, vec_ZZ_pX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; ZZ_pX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(ZZ_pX& g, long gs, const ZZ_pXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName("giant", gs)); NTL_INPUT_CHECK_ERR(s >> g); } else g = (*GiantStepFile)(gs); rem(g, g, F); } static void FetchBabySteps(vec_ZZ_pX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName("baby", i)); NTL_INPUT_CHECK_ERR(s >> v[i]); } else v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_ZZ_pX BabyStep; FetchBabySteps(BabyStep, k); vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize); ZZ_pX f; f = ff; ZZ_pXModulus F; build(F, f); ZZ_pX g; ZZ_pX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == ZZ_pX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff, long k, long gs, const vec_ZZ_pX& BabyStep, long verbose) { vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize); ZZ_pX f; f = ff; ZZ_pXModulus F; build(F, f); ZZ_pX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == ZZ_pX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_ZZ_pX_long& factors, const vec_pair_ZZ_pX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_ZZ_pX BabyStep; long i; for (i = 0; i < u.length(); i++) { const ZZ_pX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; ZZ_pX h1; if (CalcTableSize(deg(f), k + l - 1) > ZZ_pXFileThresh) use_files = 1; else use_files = 0; FileList flist; vec_ZZ_pX local_BabyStepFile; vec_ZZ_pX local_GiantStepFile; BabyStepFile = &local_BabyStepFile; GiantStepFile = &local_GiantStepFile; GenerateBabySteps(h1, f, h, k, flist, verbose); GenerateGiantSteps(f, h1, l, flist, verbose); vec_pair_ZZ_pX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); } NTL_END_IMPL ntl-11.5.1/src/fileio.cpp0000644417616742025610000000527014064716022016723 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include #include NTL_START_IMPL void OpenWrite(ofstream& s, const char *name) { s.open(name, std::ios::out); if (!s) { FileError("write open failed"); } } void OpenWrite(ofstream& s, const char *name, FileList& flist) { // post condition: file is successfully opened iff // name is added to flist (even if exception is thrown). // We do the AddFile first, since that can conceivably fail. flist.AddFile(name); s.open(name, std::ios::out); if (!s) { flist.RemoveLast(); FileError("write open failed"); } } void OpenRead(ifstream& s, const char *name) { s.open(name, std::ios::in); if (!s) { FileError("read open failed"); } } void CloseWrite(ofstream& s) { s.close(); if (s.fail()) FileError("close failed"); } void FileList::AddFile(const char *name) { Vec item; item.SetLength(strlen(name)+1); strcpy(item.elts(), name); data.append(item); } void FileList::RemoveLast() { data.SetLength(data.length()-1); } FileList::~FileList() { long i, n; n = data.length(); for (i = 0; i < n; i++) remove(data[i].elts()); } const char *FileName(const char* stem, long d) { NTL_TLS_LOCAL(std::string, sbuf); std::stringstream ss; ss << "tmp-ntl-" << stem; ss << "-" << std::setfill('0') << std::setw(5) << d << "-"; sbuf = ss.str() + UniqueID(); return sbuf.c_str(); } // UniqueID: // // builds a string of the form cnt-time-clock-pid-tid, where // - cnt is a global counter // - time is the value returned by time(0) // - clock is the value returned by clock() // - pid is the value returned by getpid() (or "0" if getpid() // is not available) // - tid is the value returned by this_thread::get_id() // (or "0" if not using threads) // each thread should have its own unique ID, which is guaranteed // to be unique across all threads in a process, and which // is hopefully unique across the entire system (but this // harder to guarantee) const std::string& UniqueID() { static AtomicCounter cnt; // a GLOBAL counter NTL_TLS_LOCAL(std::string, ID); NTL_TLS_LOCAL_INIT(bool, initialized, (false)); NTL_TLS_LOCAL_INIT(unsigned long, local_cnt, (cnt.inc())); NTL_TLS_LOCAL_INIT(unsigned long, local_time, (time(0))); NTL_TLS_LOCAL_INIT(unsigned long, local_clock, (clock())); if (!initialized) { std::stringstream ss; ss << local_cnt << "-" << local_time << "-" << local_clock << "-" << GetPID() << "-" << CurrentThreadID(); ID = ss.str(); initialized = true; } return ID; } NTL_END_IMPL ntl-11.5.1/src/lip.cpp0000644417616742025610000060714514064716022016251 0ustar gid-shoupvpug-gid-shoupv /* * This is a "wrapper" layer that builds on top of the "mpn" layer of gmp. * This layer provides much of the same functionality of the "mpz" * layer of gmp, but the interface it provides is much more like * the interface provided by lip. * * This layer was written under the following assumptions about gmp: * 1) mp_limb_t is an unsigned integral type * 2) sizeof(mp_limb_t) == sizeof(long) or sizeof(mp_limb_t) == 2*sizeof(long) * 3) the number of bits of an mp_limb_t is equal to that of a long, * or twice that of a long * 4) the number of bits of a gmp radix is equal to the number of bits * of an mp_limb_t * * Except for assumption (1), these assumptions are verified in the * installation script, and they should be universally satisfied in practice, * except when gmp is built using the proposed, new "nail" fetaure * (in which some bits of an mp_limb_t are unused). * The code here will not work properly with the "nail" feature; * however, I have (attempted to) identify all such problem spots, * and any other places where assumptions (2-4) are made, * with a comment labeled "DIRT". */ #include #include #include #include #include #ifdef NTL_GMP_LIP #include #if (__GNU_MP_VERSION < 5) #error "GMP version 5.0.0 or later required" #endif #endif NTL_IMPORT_FROM_STD NTL_USE_NNS #if (defined(NTL_HAVE_LL_TYPE) && NTL_BITS_PER_LIMB_T == NTL_BITS_PER_LONG) #define NTL_VIABLE_LL #endif #ifdef NTL_GMP_LIP typedef mp_limb_t _ntl_limb_t; #define NTL_MPN(fun) mpn_ ## fun #else typedef unsigned long _ntl_limb_t; typedef long _ntl_signed_limb_t; #define NTL_MPN(fun) _ntl_mpn_ ## fun #endif typedef _ntl_limb_t *_ntl_limb_t_ptr; #define NTL_NAIL_BITS (NTL_BITS_PER_LIMB_T-NTL_ZZ_NBITS) #define NTL_LIMB_MASK (_ntl_limb_t(-1) >> NTL_NAIL_BITS) #define NTL_ZZ_RADIX (NTL_LIMB_MASK+_ntl_limb_t(1)) // this will be zero if no nails #define NTL_ZZ_FRADIX_INV (1.0/NTL_ZZ_FRADIX) #if (NTL_ZZ_NBITS > NTL_BITS_PER_LONG-2) static inline double DBL(_ntl_limb_t x) { return double(x); } #else // this might be a bit faster static inline double DBL(_ntl_limb_t x) { return double(long(x)); } #endif // DIRT: we assume that NTL_BITS_PER_LIMB_T >= BITS_PER_LONG static inline _ntl_limb_t ABS(long x) { if (x < 0) return -_ntl_limb_t(x); // careful ! else return _ntl_limb_t(x); } static inline long XOR(long a, long b) { return a ^ b; } static inline _ntl_limb_t CLIP(_ntl_limb_t a) { return a & NTL_LIMB_MASK; } static inline _ntl_limb_t XCLIP(_ntl_limb_t a) { return a & ~NTL_LIMB_MASK; } #if (NTL_BITS_PER_LIMB_T == NTL_BITS_PER_LONG) static inline long COUNT_BITS(_ntl_limb_t x) { return _ntl_count_bits(x); } #else static inline long COUNT_BITS(_ntl_limb_t x) { if (!x) { return 0; } long res = NTL_BITS_PER_LIMB_T; while (x < (_ntl_limb_t(1) << (NTL_BITS_PER_LIMB_T-1))) { x <<= 1; res--; } return res; } #endif #ifndef NTL_GMP_LIP /* * Kind of a "mini LIP" --- this implements some of GMP's mpn interface using * a floating point strategy similar to Arjen Lenstra's LIP library. However, * most of the low-level details have evolved over time, so very little of Lenstra's * original code is actually left here. * */ _ntl_signed_limb_t _ntl_mpn_cmp(const _ntl_limb_t *s1p, const _ntl_limb_t *s2p, long n) { for (long i = n-1; i >= 0; i--) { _ntl_signed_limb_t diff = _ntl_signed_limb_t(s1p[i]) - _ntl_signed_limb_t(s2p[i]); if (diff) return diff; } return 0; } _ntl_limb_t _ntl_mpn_lshift (_ntl_limb_t *rp, const _ntl_limb_t *up, long n, long cnt) { _ntl_limb_t high_limb, low_limb; long tnc; _ntl_limb_t retval; up += n; rp += n; tnc = NTL_ZZ_NBITS - cnt; low_limb = *--up; retval = low_limb >> tnc; high_limb = CLIP(low_limb << cnt); while (--n != 0) { low_limb = *--up; *--rp = high_limb | (low_limb >> tnc); high_limb = CLIP(low_limb << cnt); } *--rp = high_limb; return retval; } _ntl_limb_t _ntl_mpn_rshift(_ntl_limb_t *rp, const _ntl_limb_t *up, long n, long cnt) { _ntl_limb_t high_limb, low_limb; long tnc; _ntl_limb_t retval; tnc = NTL_ZZ_NBITS - cnt; high_limb = *up++; retval = CLIP(high_limb << tnc); low_limb = high_limb >> cnt; while (--n != 0) { high_limb = *up++; *rp++ = low_limb | CLIP(high_limb << tnc); low_limb = high_limb >> cnt; } *rp = low_limb; return retval; } _ntl_limb_t _ntl_mpn_add_1 (_ntl_limb_t *rp, const _ntl_limb_t *ap, long n, _ntl_limb_t b) { long i; if (rp != ap) { i = 0; do { _ntl_limb_t r = ap[i] + b; rp[i] = CLIP(r); b = r >> NTL_ZZ_NBITS; } while (++i < n); return b; } else { i = 0; do { if (!b) return 0; _ntl_limb_t r = ap[i] + b; rp[i] = CLIP(r); b = r >> NTL_ZZ_NBITS; } while (++i < n); return b; } } _ntl_limb_t _ntl_mpn_add_n (_ntl_limb_t *rp, const _ntl_limb_t *ap, const _ntl_limb_t *bp, long n) { long i; _ntl_limb_t cy; for (i = 0, cy = 0; i < n; i++) { _ntl_limb_t sum = ap[i] + bp[i] + cy; rp[i] = CLIP(sum); cy = sum >> NTL_ZZ_NBITS; } return cy; } _ntl_limb_t _ntl_mpn_add (_ntl_limb_t *rp, const _ntl_limb_t *ap, long an, const _ntl_limb_t *bp, long bn) { _ntl_limb_t cy; cy = _ntl_mpn_add_n (rp, ap, bp, bn); if (an > bn) cy = _ntl_mpn_add_1 (rp + bn, ap + bn, an - bn, cy); return cy; } _ntl_limb_t _ntl_mpn_sub_1 (_ntl_limb_t *rp, const _ntl_limb_t *ap, long n, _ntl_limb_t b) { long i; if (rp != ap) { i = 0; do { _ntl_limb_t r = ap[i] - b; rp[i] = CLIP(r); b = (r >> NTL_ZZ_NBITS) & 1; } while (++i < n); return b; } else { i = 0; do { if (!b) return 0; _ntl_limb_t r = ap[i] - b; rp[i] = CLIP(r); b = (r >> NTL_ZZ_NBITS) & 1; } while (++i < n); return b; } } _ntl_limb_t _ntl_mpn_sub_n (_ntl_limb_t *rp, const _ntl_limb_t *ap, const _ntl_limb_t *bp, long n) { long i; _ntl_limb_t cy; for (i = 0, cy = 0; i < n; i++) { _ntl_limb_t sum = ap[i] - bp[i] - cy; rp[i] = CLIP(sum); cy = (sum >> NTL_ZZ_NBITS) & 1; } return cy; } _ntl_limb_t _ntl_mpn_sub (_ntl_limb_t *rp, const _ntl_limb_t *ap, long an, const _ntl_limb_t *bp, long bn) { _ntl_limb_t cy; cy = _ntl_mpn_sub_n (rp, ap, bp, bn); if (an > bn) cy = _ntl_mpn_sub_1 (rp + bn, ap + bn, an - bn, cy); return cy; } #ifndef NTL_HAVE_LL_TYPE // (t, a) = b*d + a + t #if 0 // This is true to the original LIP spirit, and should // still work assuming we have something close to the correct // relative precision. However, I find that on both haswell and skylake, // it makes multiplication about twice as slow, which is a bit surprising // I think the main issue is the extra int to double conversion. static inline void _ntl_addmulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { _ntl_limb_t t1 = b * d; _ntl_limb_t t2 = a + t; _ntl_limb_t t3 = CLIP(t1+t2); double d1 = DBL(b) * DBL(d); double d2 = d1 + double( _ntl_signed_limb_t(t2) - _ntl_signed_limb_t(t3) + _ntl_signed_limb_t(NTL_ZZ_RADIX/2) ); double d3 = d2 * NTL_ZZ_FRADIX_INV; t = _ntl_signed_limb_t(d3); a = t3; } #else #if (NTL_NAIL_BITS == 2) static inline void _ntl_addmulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { _ntl_limb_t t1 = b * d; _ntl_limb_t t2 = _ntl_signed_limb_t( DBL(b)*(DBL(d)*NTL_ZZ_FRADIX_INV) ) - 1; t2 = t2 + ( (t1 - (t2 << NTL_ZZ_NBITS)) >> NTL_ZZ_NBITS ); t1 = CLIP(t1) + a + t; t = t2 + (t1 >> NTL_ZZ_NBITS); a = CLIP(t1); } #else static inline void _ntl_addmulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { _ntl_limb_t t1 = b * d + a + t; _ntl_limb_t t2 = _ntl_signed_limb_t( DBL(b)*(DBL(d)*NTL_ZZ_FRADIX_INV) ) - 1; t = t2 + ( (t1 - (t2 << NTL_ZZ_NBITS)) >> NTL_ZZ_NBITS ); a = CLIP(t1); } #endif #endif // (t, a) = b*b + a static inline void _ntl_addmulpsq(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t& t) { _ntl_limb_t t1 = b*b + a; _ntl_limb_t t2 = _ntl_signed_limb_t( DBL(b)*(DBL(b)*NTL_ZZ_FRADIX_INV) ) - 1; t = t2 + ((t1 - (t2 << NTL_ZZ_NBITS)) >> NTL_ZZ_NBITS); a = CLIP(t1); } // (t, a) = b*d + t static inline void _ntl_mulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { _ntl_limb_t t1 = b*d + t; _ntl_limb_t t2 = _ntl_signed_limb_t( DBL(b)*(DBL(d)*NTL_ZZ_FRADIX_INV) ) - 1; t = t2 + ((t1 - (t2 << NTL_ZZ_NBITS)) >> NTL_ZZ_NBITS); a = CLIP(t1); } // (t, a) = b*(-d) + a + t, where t is "signed" static inline void _ntl_submulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { _ntl_limb_t t1 = b*(NTL_ZZ_RADIX-d) + a; _ntl_limb_t t2 = _ntl_signed_limb_t( DBL(b)*(DBL(NTL_ZZ_RADIX-d)*NTL_ZZ_FRADIX_INV) ) - 1; _ntl_limb_t lo = CLIP(t1); _ntl_limb_t hi = t2 + ((t1 - (t2 << NTL_ZZ_NBITS)) >> NTL_ZZ_NBITS); lo += t; a = CLIP(lo); t = hi - b - (lo >> (NTL_BITS_PER_LIMB_T-1)); } #else // (t, a) = b*d + a + t static inline void _ntl_addmulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { ll_type x; ll_imul(x, b, d); ll_add(x, a+t); a = CLIP(ll_get_lo(x)); t = ll_rshift_get_lo(x); } // (t, a) = b*b + a static inline void _ntl_addmulpsq(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t& t) { ll_type x; ll_imul(x, b, b); ll_add(x, a); a = CLIP(ll_get_lo(x)); t = ll_rshift_get_lo(x); } // (t, a) = b*d + t static inline void _ntl_mulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { ll_type x; ll_imul(x, b, d); ll_add(x, t); a = CLIP(ll_get_lo(x)); t = ll_rshift_get_lo(x); } // (t, a) = b*(-d) + a + t, where t is "signed" static inline void _ntl_submulp(_ntl_limb_t& a, _ntl_limb_t b, _ntl_limb_t d, _ntl_limb_t& t) { ll_type x; ll_imul(x, b, NTL_ZZ_RADIX-d); _ntl_limb_t lo = CLIP(ll_get_lo(x)); _ntl_limb_t hi = ll_rshift_get_lo(x); lo += a+t; a = CLIP(lo); // NOTE: the high-order bits of lo encode 0, 1, or -1 #if (!defined(NTL_CLEAN_INT) && NTL_ARITH_RIGHT_SHIFT) t = hi - b + (cast_signed(lo) >> NTL_ZZ_NBITS); #else t = hi - b + ((lo + NTL_ZZ_RADIX) >> NTL_ZZ_NBITS) - 1; #endif } #endif void _ntl_addmulsq(long n, _ntl_limb_t *a, const _ntl_limb_t *b) { _ntl_limb_t s = b[0]; _ntl_limb_t carry = 0; for (long i = 0; i < n; i++) { _ntl_addmulp(a[i], b[i+1], s, carry); } a[n] += carry; } _ntl_limb_t _ntl_mpn_mul_1 (_ntl_limb_t* rp, const _ntl_limb_t* up, long n, _ntl_limb_t vl) { _ntl_limb_t carry = 0; for (long i = 0; i < n; i++) _ntl_mulp(rp[i], up[i], vl, carry); return carry; } _ntl_limb_t _ntl_mpn_addmul_1 (_ntl_limb_t* rp, const _ntl_limb_t* up, long n, _ntl_limb_t vl) { _ntl_limb_t carry = 0; for (long i = 0; i < n; i++) _ntl_addmulp(rp[i], up[i], vl, carry); return carry; } _ntl_limb_t _ntl_mpn_submul_1 (_ntl_limb_t* rp, const _ntl_limb_t* up, long n, _ntl_limb_t vl) { _ntl_limb_t carry = 0; for (long i = 0; i < n; i++) { _ntl_submulp(rp[i], up[i], vl, carry); } return -carry; } // compute (carry, rp[n-1], ..., rp[0]) = (rp[n-1], ..., rp[0], shift_in) // - (up[n-1], ..., up[0]) * vl, // and return carry (which may be negative, but stored as an unsigned). No // aliasing is allowed. This is a special-purpose used by the tdiv_qr routine, // to avoid allocating extra buffer space and extra shifting. It is not a part // of GMP interface. _ntl_limb_t _ntl_mpn_shift_submul_1(_ntl_limb_t* NTL_RESTRICT rp, _ntl_limb_t shift_in, const _ntl_limb_t* NTL_RESTRICT up, long n, _ntl_limb_t vl) { #if 0 _ntl_limb_t carry = 0; for (long i = 0; i < n; i++) { _ntl_submulp(shift_in, up[i], vl, carry); _ntl_swap(shift_in, rp[i]); } return carry + shift_in; #else // NOTE: loop unrolling seems to help a little bit _ntl_limb_t carry = 0; long i = 0; for (; i <= n-4; i += 4) { _ntl_submulp(shift_in, up[i], vl, carry); _ntl_limb_t tmp1 = rp[i]; rp[i] = shift_in; _ntl_submulp(tmp1, up[i+1], vl, carry); _ntl_limb_t tmp2 = rp[i+1]; rp[i+1] = tmp1; _ntl_submulp(tmp2, up[i+2], vl, carry); _ntl_limb_t tmp3 = rp[i+2]; rp[i+2] = tmp2; _ntl_submulp(tmp3, up[i+3], vl, carry); shift_in = rp[i+3]; rp[i+3] = tmp3; } for (; i < n; i++) { _ntl_submulp(shift_in, up[i], vl, carry); _ntl_swap(shift_in, rp[i]); } return carry + shift_in; #endif } static inline void _ntl_mpn_base_sqr(_ntl_limb_t *c, const _ntl_limb_t *a, long sa) { long sc = 2*sa; for (long i = 0; i < sc; i++) c[i] = 0; _ntl_limb_t carry = 0; for (long i = 0, j = 0; j < sa; i += 2, j++) { _ntl_limb_t uc, t; uc = carry + (c[i] << 1); t = CLIP(uc); _ntl_addmulpsq(t, a[j], carry); c[i] = t; _ntl_addmulsq(sa-j-1, c+i+1, a+j); uc = (uc >> NTL_ZZ_NBITS) + (c[i+1] << 1); uc += carry; carry = uc >> NTL_ZZ_NBITS; c[i+1] = CLIP(uc); } } static inline _ntl_limb_t _ntl_mpn_base_mul (_ntl_limb_t* rp, const _ntl_limb_t* up, long un, const _ntl_limb_t* vp, long vn) { rp[un] = _ntl_mpn_mul_1 (rp, up, un, vp[0]); while (--vn >= 1) { rp += 1, vp += 1; rp[un] = _ntl_mpn_addmul_1 (rp, up, un, vp[0]); } return rp[un]; } // Karatsuba implementation: I didn't really want to port this // implementation, but some higher-level code assumes that // multiplication is subquadratic static long kar_fold(_ntl_limb_t *T, const _ntl_limb_t *b, long sb, long hsa) { _ntl_limb_t carry = 0; for (long i = 0; i < sb-hsa; i++) { _ntl_limb_t t = b[i] + b[i+hsa] + carry; carry = t >> NTL_ZZ_NBITS; T[i] = CLIP(t); } for (long i = sb-hsa; i < hsa; i++) { _ntl_limb_t t = b[i] + carry; carry = t >> NTL_ZZ_NBITS; T[i] = CLIP(t); } if (carry) { T[hsa] = carry; return hsa+1; } else { return hsa; } } static void kar_sub(_ntl_limb_t *T, const _ntl_limb_t *c, long sc) { _ntl_limb_t carry = 0; for (long i = 0; i < sc; i++) { _ntl_limb_t t = T[i] - c[i] - carry; carry = (t >> NTL_ZZ_NBITS) & 1; T[i] = CLIP(t); } for (long i = sc; carry; i++) { _ntl_limb_t t = T[i] - 1; carry = (t >> NTL_ZZ_NBITS) & 1; T[i] = CLIP(t); } } static void kar_add(_ntl_limb_t *c, const _ntl_limb_t *T, long sT, long hsa) { c += hsa; _ntl_limb_t carry = 0; while (sT > 0 && T[sT-1] == 0) sT--; for (long i = 0; i < sT; i++) { _ntl_limb_t t = c[i] + T[i] + carry; carry = t >> NTL_NBITS; c[i] = CLIP(t); } for (long i = sT; carry; i++) { _ntl_limb_t t = c[i] + 1; carry = t >> NTL_NBITS; c[i] = CLIP(t); } } static void kar_fix(_ntl_limb_t *c, const _ntl_limb_t *T, long sT, long hsa) { for (long i = 0; i < hsa; i++) { c[i] = T[i]; } _ntl_limb_t carry = 0; for (long i = hsa; i < sT; i++) { _ntl_limb_t t = c[i] + T[i] + carry; carry = t >> NTL_NBITS; c[i] = CLIP(t); } for (long i = sT; carry; i++) { _ntl_limb_t t = c[i] + 1; carry = t >> NTL_NBITS; c[i] = CLIP(t); } } #define KARX (16) static void kar_mul(_ntl_limb_t *c, const _ntl_limb_t *a, long sa, const _ntl_limb_t *b, long sb, _ntl_limb_t *stk, long sp) { if (sa < sb) { _ntl_swap(a, b); _ntl_swap(sa, sb); } if (sb < KARX) { /* classic algorithm */ _ntl_mpn_base_mul(c, a, sa, b, sb); } else { long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ _ntl_limb_t *T1, *T2, *T3; /* allocate space */ sp -= (hsa + 1) + ((hsa << 1) + 2); if (sp < 0) TerminalError("internal error: kmem overflow"); T1 = c; T2 = stk; stk += hsa + 1; T3 = stk; stk += (hsa << 1) + 2; /* compute T1 = a_lo + a_hi */ long sT1 = kar_fold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ long sT2 = kar_fold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ kar_mul(T3, T1, sT1, T2, sT2, stk, sp); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ kar_mul(c + (hsa << 1), a+hsa, sa-hsa, b+hsa, sb-hsa, stk, sp); kar_sub(T3, c + (hsa << 1), sa+sb-2*hsa); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ kar_mul(c, a, hsa, b, hsa, stk, sp); kar_sub(T3, c, 2*hsa); /* finally, add T3 * NTL_RADIX^{hsa} to c */ kar_add(c, T3, sT1+sT2, hsa); } else { /* degenerate case */ _ntl_limb_t *T; sp -= (sb + hsa); if (sp < 0) TerminalError("internal error: kmem overflow"); T = stk; stk += sb + hsa; /* recursively compute b*a_hi into high part of c */ kar_mul(c + hsa, a+hsa, sa-hsa, b, sb, stk, sp); /* recursively compute b*a_lo into T */ kar_mul(T, a, hsa, b, sb, stk, sp); /* fix-up result */ kar_fix(c, T, hsa+sb, hsa); } } } NTL_TLS_GLOBAL_DECL(Vec<_ntl_limb_t>, kmem) static void kar_mul(_ntl_limb_t *c, const _ntl_limb_t *a, long sa, const _ntl_limb_t *b, long sb) { long n = sa; long sp = 0; do { long hn = (n+1) >> 1; sp += hn * 3 + 7; n = hn+1; } while (n >= KARX); NTL_TLS_GLOBAL_ACCESS(kmem); Vec<_ntl_limb_t>::Watcher kmem_watcher(kmem); kmem.SetLength(sp); kar_mul(c, a, sa, b, sb, kmem.elts(), sp); } #define KARSX (32) static void kar_sq(_ntl_limb_t *c, const _ntl_limb_t *a, long sa, _ntl_limb_t *stk, long sp) { if (sa < KARSX) { /* classic algorithm */ _ntl_mpn_base_sqr(c, a, sa); } else { long hsa = (sa + 1) >> 1; _ntl_limb_t *T1, *T2; sp -= (hsa << 1) + 2; if (sp < 0) TerminalError("internal error: kmem overflow"); T1 = c; T2 = stk; stk += (hsa << 1) + 2; long sT1 = kar_fold(T1, a, sa, hsa); kar_sq(T2, T1, sT1, stk, sp); kar_sq(c + (hsa << 1), a+hsa, sa-hsa, stk, sp); kar_sub(T2, c + (hsa << 1), 2*(sa-hsa)); kar_sq(c, a, hsa, stk, sp); kar_sub(T2, c, 2*hsa); kar_add(c, T2, 2*sT1, hsa); } } static void kar_sq(_ntl_limb_t *c, const _ntl_limb_t *a, long sa) { long n = sa; long sp = 0; do { long hn = (n+1) >> 1; sp += 2*hn + 5; n = hn+1; } while (n >= KARSX); NTL_TLS_GLOBAL_ACCESS(kmem); Vec<_ntl_limb_t>::Watcher kmem_watcher(kmem); kmem.SetLength(sp); kar_sq(c, a, sa, kmem.elts(), sp); } void _ntl_mpn_sqr(_ntl_limb_t *c, const _ntl_limb_t *a, long sa) { if (sa >= KARSX) { kar_sq(c, a, sa); return; } _ntl_mpn_base_sqr(c, a, sa); } // Like the corresponding GMP routine, this assumes un >= vn >= 1 _ntl_limb_t _ntl_mpn_mul (_ntl_limb_t* rp, const _ntl_limb_t* up, long un, const _ntl_limb_t* vp, long vn) { if (up == vp && un == vn) { _ntl_mpn_sqr(rp, up, un); return rp[2*un-1]; } if (vn >= KARX) { kar_mul(rp, up, un, vp, vn); return rp[un+vn-1]; } return _ntl_mpn_base_mul(rp, up, un, vp, vn); } // (quot, numhigh) = (num / denom, num % denom), where num = numhigh*RADIX + numlow // deninv should be pre-computed as 1/double(denom). // Normally, this should be invoked with numhigh < denom, which guarantees // that quot < RADIX. However, this implementation work with quot as large as RADIX+1, // which could exploited in the general division routine (but it currently is not). // NOTE: these are the only routines left that completely rely on the assumption // that NTL_ZZ_NBITS is less than floating point precision. It would be possible // to increase NTL_ZZ_NBITS if defined(NTL_HAVE_LL_TYPE), but this is not something // I want to spend time on. Use GMP instead! static inline void _ntl_div21p(_ntl_limb_t& numhigh, _ntl_limb_t numlow, _ntl_limb_t denom, double deninv, _ntl_limb_t& quot) { _ntl_limb_t q21 = _ntl_signed_limb_t(((NTL_ZZ_FRADIX * DBL(numhigh)) + DBL(numlow))* deninv); _ntl_limb_t r21 = (numhigh << NTL_ZZ_NBITS) + numlow - denom*q21; r21 = sp_CorrectDeficitQuo(q21, r21, _ntl_signed_limb_t(denom)); r21 = sp_CorrectExcessQuo (q21, r21, _ntl_signed_limb_t(denom)); quot = q21; numhigh = r21; } // same as above, but quot not computed static inline void _ntl_rem21p(_ntl_limb_t& numhigh, _ntl_limb_t numlow, _ntl_limb_t denom, double deninv) { _ntl_limb_t q21 = _ntl_signed_limb_t(((NTL_ZZ_FRADIX * DBL(numhigh)) + DBL(numlow))* deninv); _ntl_limb_t r21 = (numhigh << NTL_ZZ_NBITS) + numlow - denom*q21; r21 = sp_CorrectDeficit(r21, _ntl_signed_limb_t(denom)); r21 = sp_CorrectExcess (r21, _ntl_signed_limb_t(denom)); numhigh = r21; } // same as above, but remainder not computed, returns quot static inline _ntl_limb_t _ntl_quo21p(_ntl_limb_t numhigh, _ntl_limb_t numlow, _ntl_limb_t denom, double deninv) { _ntl_limb_t q21 = _ntl_signed_limb_t(((NTL_ZZ_FRADIX * DBL(numhigh)) + DBL(numlow))* deninv); _ntl_limb_t r21 = (numhigh << NTL_ZZ_NBITS) + numlow - denom*q21; r21 = sp_CorrectDeficitQuo(q21, r21, _ntl_signed_limb_t(denom)); r21 = sp_CorrectExcessQuo (q21, r21, _ntl_signed_limb_t(denom)); return q21; } _ntl_limb_t _ntl_mpn_divmod_1 (_ntl_limb_t *q, const _ntl_limb_t *a, long sa, _ntl_limb_t d) { double dinv = 1.0/DBL(d); _ntl_limb_t carry = 0; if (a[sa-1] < d) { carry = a[sa-1]; q[sa-1] = 0; sa--; } for (long i = sa-1; i >= 0; i--) { _ntl_div21p(carry, a[i], d, dinv, q[i]); } return carry; } _ntl_limb_t _ntl_mpn_mod_1 (const _ntl_limb_t *a, long sa, _ntl_limb_t d) { double dinv = 1.0/DBL(d); _ntl_limb_t carry = 0; if (a[sa-1] < d) { carry = a[sa-1]; sa--; } for (long i = sa-1; i >= 0; i--) { _ntl_rem21p(carry, a[i], d, dinv); } return carry; } // NOTE: no aliasing allowed (more recent versions of GMP allow a==r) void _ntl_mpn_tdiv_qr (_ntl_limb_t *q, _ntl_limb_t *r,long /* qxn */, const _ntl_limb_t *a, long sa, const _ntl_limb_t *d, long sd) { if (sd == 1) { r[0] = _ntl_mpn_divmod_1(q, a, sa, d[0]); return; } // compute dhi = high order NTL_ZZ_NBITS of (d[sd-1], ..., d[0]) _ntl_limb_t d1 = d[sd-1]; _ntl_limb_t d0 = d[sd-2]; long dbits = COUNT_BITS(d1); _ntl_limb_t dhi = (d1 << (NTL_ZZ_NBITS-dbits)) | (d0 >> dbits); double dhi_inv = 1.0/DBL(dhi); // initialize buffer to (0, a[sa-1], ..., a[sa-sd+1]) for (long j = 0; j < sd-1; j++) r[j] = a[sa-sd+1+j]; r[sd-1] = 0; for (long i = sa-sd; i >= 0; i--) { // compute (rhi1, rhi0) = high order 2*NTL_ZZ_NBITS of buffer _ntl_limb_t r2, r1, r0; r2 = r[sd-1]; r1 = r[sd-2]; r0 = sd > 2 ? r[sd-3] : a[i]; _ntl_limb_t rhi1 = (r2 << (NTL_ZZ_NBITS-dbits)) | (r1 >> dbits); _ntl_limb_t rhi0 = CLIP(r1 << (NTL_ZZ_NBITS-dbits)) | (r0 >> dbits); // compute estimate for quotient digit: it may be too large by at most 2 _ntl_limb_t qdigit; if (rhi1 >= dhi) qdigit = NTL_ZZ_RADIX-1; else qdigit = _ntl_quo21p(rhi1, rhi0, dhi, dhi_inv); _ntl_limb_t carry = _ntl_mpn_shift_submul_1(r, a[i], d, sd, qdigit); while (carry) { // loop body executes at most twice carry += _ntl_mpn_add_n(r, r, d, sd); qdigit--; } q[i] = qdigit; } } #endif /* A bigint is represented as two long's, ALLOC and SIZE, followed by a * vector DATA of _ntl_limb_t's. * * ALLOC is of the form * (alloc << 2) | continue_flag | frozen_flag * where * - alloc is the number of allocated _ntl_limb_t's, * - continue flag is either 2 or 0, * - frozen_flag is either 1 or 0. * If frozen_flag is set, then the space for this bigint is *not* * managed by the _ntl_gsetlength and _ntl_gfree routines, * but are instead managed by the vec_ZZ_p and ZZVec routines. * The continue_flag is only set when the frozen_flag is set. * * SIZE is the number of _ntl_limb_t's actually * used by the bigint, with the sign of SIZE having * the sign of the bigint. * Note that the zero bigint is represented as SIZE=0. * * Bigint's are accessed through a handle, which is pointer to void. * A null handle logically represents the bigint zero. * This is done so that the interface presented to higher level * routines is essentially the same as that of NTL's traditional * long integer package. * * The components ALLOC, SIZE, and DATA are all accessed through * macros using pointer casts. While all of may seem a bit dirty, * it should be quite portable: objects are never referenced * through pointers of different types, and no alignmement * problems should arise. * * DIRT: This rule is broken in the file g_lip.h: the inline definition * of _ntl_gmaxalloc in that file has the definition of ALLOC pasted in. * * Actually, _ntl_limb_t is usually the type unsigned long. * However, on some 64-bit platforms, the type long is only 32 bits, * and gmp makes _ntl_limb_t unsigned long long in this case. * This is fairly rare, as the industry standard for Unix is to * have 64-bit longs on 64-bit machines. */ /* DIRT: STORAGE computes the number of bytes to allocate for a bigint * of maximal SIZE len. This should be computed so that one * can store several such bigints in a contiguous array * of memory without breaking any alignment requirements. * Currently, it is assumed (and explicitly checked in the NTL installation * script) that sizeof(_ntl_limb_t) is either sizeof(long) or * 2*sizeof(long), and therfore, nothing special needs to * be done to enfoce alignment requirements. If this assumption * should change, then the storage layout for bigints must be * re-designed. */ static inline long& ALLOC(_ntl_gbigint p) { return p->alloc_; } static inline long& SIZE(_ntl_gbigint p) { return p->size_; } static inline _ntl_limb_t * DATA(_ntl_gbigint p) { return (_ntl_limb_t *) (p+1); } static inline long STORAGE(long len) { return ((long)(sizeof(_ntl_gbigint_body) + (len)*sizeof(_ntl_limb_t))); } static inline long MustAlloc(_ntl_gbigint c, long len) { return (!(c) || (ALLOC(c) >> 2) < (len)); } static inline void GET_SIZE_NEG(long& sz, long& neg, _ntl_gbigint p) { long s; s = SIZE(p); if (s < 0) { sz = -s; neg = 1; } else { sz = s; neg = 0; } } static inline void STRIP(long& sz, const _ntl_limb_t *p) { long n = sz; while (n > 0 && p[n-1] == 0) n--; sz = n; } static inline long ZEROP(_ntl_gbigint p) { return !p || !SIZE(p); } static inline long ONEP(_ntl_gbigint p) { return p && SIZE(p) == 1 && DATA(p)[0] == 1; } static inline void SWAP_BIGINT(_ntl_gbigint& a, _ntl_gbigint& b) { _ntl_gbigint t; t = a; a = b; b = t; } static inline void SWAP_LONG(long& a, long& b) { long t; t = a; a = b; b = t; } static inline void SWAP_LIMB_PTR(_ntl_limb_t_ptr& a, _ntl_limb_t_ptr& b) { _ntl_limb_t_ptr t; t = a; a = b; b = t; } static void DUMP(_ntl_gbigint a) { if (ZEROP(a)) cerr << "[]"; else { long sa = SIZE(a); if (sa < 0) { cerr << "-"; sa = -sa; } cerr << "[ "; for (long i = 0; i < sa; i++) cerr << DATA(a)[i] << " "; cerr << "]"; } cerr << "\n"; } #if (defined(NTL_CRT_ALTCODE) || defined(NTL_CRT_ALTCODE_SMALL)) #if (defined(NTL_VIABLE_LL) && NTL_NAIL_BITS == 0) // alternative CRT code is requested and viable // we do not attempt to implement this with non-empty nails, // as it is not a huge win #define NTL_TBL_CRT #else // raise an error if running the wizard #ifdef NTL_WIZARD_HACK #error "NTL_CRT_ALTCODE/NTL_CRT_ALTCODE_SMALL not viable" #endif #endif #endif #if (defined(NTL_TBL_REM) && !defined(NTL_VIABLE_LL)) #undef NTL_TBL_REM // raise an error if running the wizard #ifdef NTL_WIZARD_HACK #error "NTL_TBL_REM not viable" #endif #endif class _ntl_gbigint_watcher { public: _ntl_gbigint *watched; explicit _ntl_gbigint_watcher(_ntl_gbigint *_watched) : watched(_watched) {} ~_ntl_gbigint_watcher() { if (*watched && (ALLOC(*watched) >> 2) > NTL_RELEASE_THRESH) { _ntl_gfree(*watched); *watched = 0; } } }; class _ntl_gbigint_deleter { public: static void apply(_ntl_gbigint p) { _ntl_gfree(p); } }; typedef WrappedPtr<_ntl_gbigint_body, _ntl_gbigint_deleter> _ntl_gbigint_wrapped; static inline void _ntl_swap(_ntl_gbigint_wrapped& p, _ntl_gbigint_wrapped& q) { p.swap(q); } // GRegisters are used for local "scratch" variables. // NOTE: the first implementation of GRegister below wraps a bigint in a class // whose destructor ensures that its space is reclaimed at program/thread termination. // It really only is necesary in a multi-threading environment, but it doesn't // seem to incurr significant cost. // The second implementation does not do this wrapping, and so should not be // used in a multi-threading environment. // Both versions use a local "watcher" variable, which does the following: // when the local scope closes (e.g., the function returns), the space // for the bigint is freed *unless* it is fairly small. This balanced // approach leads significantly faster performance, while not holding // to too many resouces. // The third version releases local memory every time. It can be significantly // slower. // The fourth version --- which was the original strategy --- never releases // memory. It can be faster, but can become a memory hog. // All of this code is overly complicated, due to the fact that I'm "retrofitting" // this logic onto what was originally pure-C code. #define GRegister(x) NTL_TLS_LOCAL(_ntl_gbigint_wrapped, x); _ntl_gbigint_watcher _WATCHER__ ## x(&x) //#define GRegister(x) NTL_THREAD_LOCAL static _ntl_gbigint x(0); _ntl_gbigint_watcher _WATCHER__ ## x(&x) // #define GRegister(x) _ntl_gbigint_wrapped x(0); // #define GRegister(x) static _ntl_gbigint x = 0 #define STORAGE_OVF(len) NTL_OVERFLOW(len, sizeof(_ntl_limb_t), 2*sizeof(long)) #ifndef NTL_GMP_LIP // legacy function long _ntl_gdigit(_ntl_gbigint a, long i) { if (ZEROP(a) || i < 0) return 0; long sa = SIZE(a); if (sa < 0) sa = -sa; if (i >= sa) return 0; return DATA(a)[i]; } #endif long _ntl_gvalidate(_ntl_gbigint a) { if (ZEROP(a)) return 1; long sa = SIZE(a); if (sa < 0) sa = -sa; _ntl_limb_t *adata = DATA(a); for (long i = 0; i < sa; i++) if (XCLIP(adata[i])) return 0; if (adata[sa-1] == 0) return 0; return 1; } /* ForceNormal ensures a normalized bigint */ static void ForceNormal(_ntl_gbigint x) { long sx, xneg; _ntl_limb_t *xdata; if (!x) return; GET_SIZE_NEG(sx, xneg, x); xdata = DATA(x); STRIP(sx, xdata); if (xneg) sx = -sx; SIZE(x) = sx; } #define MIN_SETL (4) /* _ntl_gsetlength allocates a multiple of MIN_SETL digits */ void _ntl_gsetlength(_ntl_gbigint *v, long len) { _ntl_gbigint x = *v; if (len < 0) LogicError("negative size allocation in _ntl_zgetlength"); if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ResourceError("size too big in _ntl_gsetlength"); #ifdef NTL_SMALL_MP_SIZE_T /* this makes sure that numbers don't get too big for GMP */ if (len >= (1L << (NTL_BITS_PER_INT-4))) ResourceError("size too big for GMP"); #endif if (x) { long oldlen = ALLOC(x); long fixed = oldlen & 1; oldlen = oldlen >> 2; if (fixed) { if (len > oldlen) LogicError("internal error: can't grow this _ntl_gbigint"); else return; } if (len <= oldlen) return; len++; /* always allocate at least one more than requested */ oldlen = _ntl_vec_grow(oldlen); if (len < oldlen) len = oldlen; /* round up to multiple of MIN_SETL */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ResourceError("size too big in _ntl_gsetlength"); if (STORAGE_OVF(len)) ResourceError("reallocation failed in _ntl_gsetlength"); if (!(x = (_ntl_gbigint)NTL_SNS_REALLOC((void *) x, 1, STORAGE(len), 0))) { MemoryError(); } ALLOC(x) = len << 2; } else { len++; /* as above, always allocate one more than explicitly reqested */ len = ((len+(MIN_SETL-1))/MIN_SETL)*MIN_SETL; /* test len again */ if (NTL_OVERFLOW(len, NTL_ZZ_NBITS, 0)) ResourceError("size too big in _ntl_gsetlength"); if (STORAGE_OVF(len)) ResourceError("reallocation failed in _ntl_gsetlength"); if (!(x = (_ntl_gbigint)NTL_SNS_MALLOC(1, STORAGE(len), 0))) { MemoryError(); } ALLOC(x) = len << 2; SIZE(x) = 0; } *v = x; } void _ntl_gfree(_ntl_gbigint x) { if (!x) return; if (ALLOC(x) & 1) TerminalError("Internal error: can't free this _ntl_gbigint"); free((void*) x); return; } void _ntl_gswap(_ntl_gbigint *a, _ntl_gbigint *b) { if ((*a && (ALLOC(*a) & 1)) || (*b && (ALLOC(*b) & 1))) { // one of the inputs points to an bigint that is // "pinned down" in memory, so we have to swap the data, // not just the pointers GRegister(t); long sz_a, sz_b, sz; sz_a = _ntl_gsize(*a); sz_b = _ntl_gsize(*b); sz = (sz_a > sz_b) ? sz_a : sz_b; _ntl_gsetlength(a, sz); _ntl_gsetlength(b, sz); // EXCEPTIONS: all of the above ensures that swap provides strong ES _ntl_gcopy(*a, &t); _ntl_gcopy(*b, a); _ntl_gcopy(t, b); return; } SWAP_BIGINT(*a, *b); } void _ntl_gcopy(_ntl_gbigint a, _ntl_gbigint *bb) { _ntl_gbigint b; long sa, abs_sa, i; _ntl_limb_t *adata, *bdata; b = *bb; if (!a || (sa = SIZE(a)) == 0) { if (b) SIZE(b) = 0; } else { if (a != b) { if (sa >= 0) abs_sa = sa; else abs_sa = -sa; if (MustAlloc(b, abs_sa)) { _ntl_gsetlength(&b, abs_sa); *bb = b; } adata = DATA(a); bdata = DATA(b); for (i = 0; i < abs_sa; i++) bdata[i] = adata[i]; SIZE(b) = sa; } } } void _ntl_glimbs_set(const _ntl_limb_t *p, long n, _ntl_gbigint *x) { if (n < 0) LogicError("_ntl_glimbs_set: negative size"); if (n > 0 && !p) LogicError("_ntl_glimbs_set: unexpected NULL pointer"); STRIP(n, p); if (n == 0) { _ntl_gzero(x); return; } if (MustAlloc(*x, n)) _ntl_gsetlength(x, n); _ntl_limb_t *xdata = DATA(*x); for (long i = 0; i < n; i++) xdata[i] = p[i]; SIZE(*x) = n; } void _ntl_gzero(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (a) SIZE(a) = 0; } void _ntl_gone(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = 1; DATA(a)[0] = 1; } long _ntl_godd(_ntl_gbigint a) { if (ZEROP(a)) return 0; else return DATA(a)[0]&1; } long _ntl_gbit(_ntl_gbigint a, long p) { long bl; long sa; _ntl_limb_t wh; if (p < 0 || !a) return 0; bl = p/NTL_ZZ_NBITS; wh = ((_ntl_limb_t) 1) << (p - NTL_ZZ_NBITS*bl); sa = SIZE(a); if (sa < 0) sa = -sa; if (sa <= bl) return 0; if (DATA(a)[bl] & wh) return 1; return 0; } void _ntl_glowbits(_ntl_gbigint a, long b, _ntl_gbigint *cc) { _ntl_gbigint c; long bl; long wh; long sa; long i; _ntl_limb_t *adata, *cdata; if (ZEROP(a) || (b<=0)) { _ntl_gzero(cc); return; } bl = b/NTL_ZZ_NBITS; wh = b - NTL_ZZ_NBITS*bl; if (wh != 0) bl++; else wh = NTL_ZZ_NBITS; sa = SIZE(a); if (sa < 0) sa = -sa; if (sa < bl) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; /* a won't move if c aliases a */ _ntl_gsetlength(&c, bl); *cc = c; adata = DATA(a); cdata = DATA(c); for (i = 0; i < bl-1; i++) cdata[i] = adata[i]; if (wh == NTL_ZZ_NBITS) cdata[bl-1] = adata[bl-1]; else cdata[bl-1] = adata[bl-1] & ((((_ntl_limb_t) 1) << wh) - ((_ntl_limb_t) 1)); STRIP(bl, cdata); SIZE(c) = bl; } long _ntl_gslowbits(_ntl_gbigint a, long p) { GRegister(x); if (p > NTL_BITS_PER_LONG) p = NTL_BITS_PER_LONG; _ntl_glowbits(a, p, &x); return _ntl_gtoint(x); } long _ntl_gsetbit(_ntl_gbigint *a, long b) { long bl; long sa, aneg; long i; _ntl_limb_t wh, *adata, tmp; if (b<0) LogicError("_ntl_gsetbit: negative index"); bl = (b/NTL_ZZ_NBITS); wh = ((_ntl_limb_t) 1) << (b - NTL_ZZ_NBITS*bl); if (!*a) sa = aneg = 0; else GET_SIZE_NEG(sa, aneg, *a); if (sa > bl) { adata = DATA(*a); tmp = adata[bl] & wh; adata[bl] |= wh; if (tmp) return 1; return 0; } else { _ntl_gsetlength(a, bl+1); adata = DATA(*a); for (i = sa; i < bl; i++) adata[i] = 0; adata[bl] = wh; sa = bl+1; if (aneg) sa = -sa; SIZE(*a) = sa; return 0; } } long _ntl_gswitchbit(_ntl_gbigint *a, long b) { long bl; long sa, aneg; long i; _ntl_limb_t wh, *adata, tmp; if (b<0) LogicError("_ntl_gswitchbit: negative index"); bl = (b/NTL_ZZ_NBITS); wh = ((_ntl_limb_t) 1) << (b - NTL_ZZ_NBITS*bl); if (!*a) sa = aneg = 0; else GET_SIZE_NEG(sa, aneg, *a); if (sa > bl) { adata = DATA(*a); tmp = adata[bl] & wh; adata[bl] ^= wh; if (bl == sa-1) { STRIP(sa, adata); if (aneg) sa = -sa; SIZE(*a) = sa; } if (tmp) return 1; return 0; } else { _ntl_gsetlength(a, bl+1); adata = DATA(*a); for (i = sa; i < bl; i++) adata[i] = 0; adata[bl] = wh; sa = bl+1; if (aneg) sa = -sa; SIZE(*a) = sa; return 0; } } long _ntl_gweights( long aa ) { unsigned long a; long res = 0; if (aa < 0) a = -((unsigned long) aa); else a = aa; while (a) { if (a & 1) res ++; a >>= 1; } return (res); } static long gweights_mp_limb( _ntl_limb_t a ) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return (res); } long _ntl_gweight( _ntl_gbigint a ) { long i; long sa; _ntl_limb_t *adata; long res; if (!a) return (0); sa = SIZE(a); if (sa < 0) sa = -sa; adata = DATA(a); res = 0; for (i = 0; i < sa; i++) res += gweights_mp_limb(adata[i]); return (res); } long _ntl_g2log(_ntl_gbigint a) { long la; long t; if (!a) return 0; la = SIZE(a); if (la == 0) return 0; if (la < 0) la = -la; t = COUNT_BITS(DATA(a)[la-1]); return NTL_ZZ_NBITS*(la - 1) + t; } long _ntl_gmakeodd(_ntl_gbigint *nn) { _ntl_gbigint n = *nn; long shift; _ntl_limb_t *ndata; _ntl_limb_t i; if (ZEROP(n)) return (0); shift = 0; ndata = DATA(n); while (ndata[shift] == 0) shift++; i = ndata[shift]; shift = NTL_ZZ_NBITS * shift; while ((i & 1) == 0) { shift++; i >>= 1; } _ntl_grshift(n, shift, &n); return shift; } long _ntl_gnumtwos(_ntl_gbigint n) { long shift; _ntl_limb_t *ndata; _ntl_limb_t i; if (ZEROP(n)) return (0); shift = 0; ndata = DATA(n); while (ndata[shift] == 0) shift++; i = ndata[shift]; shift = NTL_ZZ_NBITS * shift; while ((i & 1) == 0) { shift++; i >>= 1; } return shift; } void _ntl_gand(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long i; long a_alias, b_alias; _ntl_limb_t *adata, *bdata, *cdata; if (ZEROP(a) || ZEROP(b)) { _ntl_gzero(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; sm = (sa > sb ? sb : sa); _ntl_gsetlength(&c, sm); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i++) cdata[i] = adata[i] & bdata[i]; STRIP(sm, cdata); SIZE(c) = sm; } void _ntl_gxor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long la; long i; long a_alias, b_alias; _ntl_limb_t *adata, *bdata, *cdata; if (ZEROP(a)) { _ntl_gcopy(b,cc); _ntl_gabs(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_gsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i ++) cdata[i] = adata[i] ^ bdata[i]; if (sa > sb) for (;i < la; i++) cdata[i] = adata[i]; else for (;i < la; i++) cdata[i] = bdata[i]; STRIP(la, cdata); SIZE(c) = la; } void _ntl_gor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { _ntl_gbigint c; long sa; long sb; long sm; long la; long i; long a_alias, b_alias; _ntl_limb_t *adata, *bdata, *cdata; if (ZEROP(a)) { _ntl_gcopy(b,cc); _ntl_gabs(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a,cc); _ntl_gabs(cc); return; } c = *cc; a_alias = (a == c); b_alias = (b == c); sa = SIZE(a); if (sa < 0) sa = -sa; sb = SIZE(b); if (sb < 0) sb = -sb; if (sa > sb) { la = sa; sm = sb; } else { la = sb; sm = sa; } _ntl_gsetlength(&c, la); if (a_alias) a = c; if (b_alias) b = c; *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); for (i = 0; i < sm; i ++) cdata[i] = adata[i] | bdata[i]; if (sa > sb) for (;i < la; i++) cdata[i] = adata[i]; else for (;i < la; i++) cdata[i] = bdata[i]; STRIP(la, cdata); SIZE(c) = la; } void _ntl_gnegate(_ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (a) SIZE(a) = -SIZE(a); } #if (NTL_ZZ_NBITS >= NTL_BITS_PER_LONG) void _ntl_gintoz(long d, _ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; } else { if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = d < 0 ? -1 : 1; DATA(a)[0] = ABS(d); } } #else void _ntl_gintoz(long d, _ntl_gbigint *aa) { long sa, i; _ntl_limb_t d1, d2; _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; return; } d1 = ABS(d); sa = 0; d2 = d1; do { d2 >>= NTL_ZZ_NBITS; sa++; } while (d2); if (MustAlloc(a, sa)) { _ntl_gsetlength(&a, sa); *aa = a; } _ntl_limb_t *adata = DATA(a); for (i = 0; i < sa; i++) { adata[i] = CLIP(d1); d1 >>= NTL_ZZ_NBITS; } if (d < 0) sa = -sa; SIZE(a) = sa; } #endif #if (NTL_ZZ_NBITS >= NTL_BITS_PER_LONG) void _ntl_guintoz(unsigned long d, _ntl_gbigint *aa) { _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; } else { if (!a) { _ntl_gsetlength(&a, 1); *aa = a; } SIZE(a) = 1; DATA(a)[0] = d; } } #else void _ntl_guintoz(unsigned long d, _ntl_gbigint *aa) { long sa, i; _ntl_limb_t d1, d2; _ntl_gbigint a = *aa; if (d == 0) { if (a) SIZE(a) = 0; return; } d1 = d; sa = 0; d2 = d1; do { d2 >>= NTL_ZZ_NBITS; sa++; } while (d2); if (MustAlloc(a, sa)) { _ntl_gsetlength(&a, sa); *aa = a; } _ntl_limb_t *adata = DATA(a); for (i = 0; i < sa; i++) { adata[i] = CLIP(d1); d1 >>= NTL_ZZ_NBITS; } SIZE(a) = sa; } #endif long _ntl_gtoint(_ntl_gbigint a) { unsigned long res = _ntl_gtouint(a); return cast_signed(res); } #if (NTL_ZZ_NBITS >= NTL_BITS_PER_LONG) unsigned long _ntl_gtouint(_ntl_gbigint a) { if (ZEROP(a)) return 0; if (SIZE(a) > 0) return DATA(a)[0]; return -DATA(a)[0]; } #else unsigned long _ntl_gtouint(_ntl_gbigint a) { if (ZEROP(a)) return 0; long sa, aneg; _ntl_limb_t *adata; GET_SIZE_NEG(sa, aneg, a); adata = DATA(a); unsigned long d = adata[0]; long bits = NTL_ZZ_NBITS; long i = 1; while (bits < NTL_BITS_PER_LONG && i < sa) { d |= adata[i] << bits; bits += NTL_ZZ_NBITS; i++; } if (aneg) d = -d; return d; } #endif long _ntl_gcompare(_ntl_gbigint a, _ntl_gbigint b) { long sa, sb, cmp; _ntl_limb_t *adata, *bdata; if (!a) sa = 0; else sa = SIZE(a); if (!b) sb = 0; else sb = SIZE(b); if (sa != sb) { if (sa > sb) return 1; else return -1; } if (sa == 0) return 0; adata = DATA(a); bdata = DATA(b); if (sa > 0) { cmp = NTL_MPN(cmp)(adata, bdata, sa); if (cmp > 0) return 1; else if (cmp < 0) return -1; else return 0; } else { cmp = NTL_MPN(cmp)(adata, bdata, -sa); if (cmp > 0) return -1; else if (cmp < 0) return 1; else return 0; } } void _ntl_gabs(_ntl_gbigint *pa) { _ntl_gbigint a = *pa; if (!a) return; if (SIZE(a) < 0) SIZE(a) = -SIZE(a); } long _ntl_gscompare(_ntl_gbigint a, long b) { if (b == 0) { long sa; if (!a) return 0; sa = SIZE(a); if (sa > 0) return 1; if (sa == 0) return 0; return -1; } else { GRegister(B); _ntl_gintoz(b, &B); return _ntl_gcompare(a, B); } } void _ntl_glshift(_ntl_gbigint n, long k, _ntl_gbigint *rres) { _ntl_gbigint res; _ntl_limb_t *ndata, *resdata, *resdata1; long limb_cnt, i, sn, nneg, sres; long n_alias; if (ZEROP(n)) { _ntl_gzero(rres); return; } res = *rres; n_alias = (n == res); if (!k) { if (!n_alias) _ntl_gcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) _ntl_gzero(rres); else _ntl_grshift(n, -k, rres); return; } GET_SIZE_NEG(sn, nneg, n); limb_cnt = ((unsigned long) k) / NTL_ZZ_NBITS; k = ((unsigned long) k) % NTL_ZZ_NBITS; sres = sn + limb_cnt; if (k != 0) sres++; if (MustAlloc(res, sres)) { _ntl_gsetlength(&res, sres); if (n_alias) n = res; *rres = res; } ndata = DATA(n); resdata = DATA(res); resdata1 = resdata + limb_cnt; if (k != 0) { _ntl_limb_t t = NTL_MPN(lshift)(resdata1, ndata, sn, k); if (t != 0) resdata[sres-1] = t; else sres--; } else { for (i = sn-1; i >= 0; i--) resdata1[i] = ndata[i]; } for (i = 0; i < limb_cnt; i++) resdata[i] = 0; if (nneg) sres = -sres; SIZE(res) = sres; } void _ntl_grshift(_ntl_gbigint n, long k, _ntl_gbigint *rres) { _ntl_gbigint res; _ntl_limb_t *ndata, *resdata, *ndata1; long limb_cnt, i, sn, nneg, sres; if (ZEROP(n)) { _ntl_gzero(rres); return; } if (!k) { if (n != *rres) _ntl_gcopy(n, rres); return; } if (k < 0) { if (k < -NTL_MAX_LONG) ResourceError("overflow in _ntl_glshift"); _ntl_glshift(n, -k, rres); return; } GET_SIZE_NEG(sn, nneg, n); limb_cnt = ((unsigned long) k) / NTL_ZZ_NBITS; sres = sn - limb_cnt; if (sres <= 0) { _ntl_gzero(rres); return; } res = *rres; if (MustAlloc(res, sres)) { /* n won't move if res aliases n */ _ntl_gsetlength(&res, sres); *rres = res; } ndata = DATA(n); resdata = DATA(res); ndata1 = ndata + limb_cnt; k = ((unsigned long) k) % NTL_ZZ_NBITS; if (k != 0) { NTL_MPN(rshift)(resdata, ndata1, sres, k); if (resdata[sres-1] == 0) sres--; } else { for (i = 0; i < sres; i++) resdata[i] = ndata1[i]; } if (nneg) sres = -sres; SIZE(res) = sres; } void _ntl_gadd(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, aneg, sb, bneg, sc, cmp; _ntl_limb_t *adata, *bdata, *cdata, carry; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gcopy(b, cc); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (sa < sb) { SWAP_BIGINT(a, b); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); } /* sa >= sb */ c = *cc; a_alias = (a == c); b_alias = (b == c); if (aneg == bneg) { /* same sign => addition */ sc = sa + 1; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); carry = NTL_MPN(add)(cdata, adata, sa, bdata, sb); if (carry) cdata[sc-1] = carry; else sc--; if (aneg) sc = -sc; SIZE(c) = sc; } else { /* opposite sign => subtraction */ sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa > sb) cmp = 1; else cmp = NTL_MPN(cmp)(adata, bdata, sa); if (cmp == 0) { SIZE(c) = 0; } else { if (cmp < 0) cmp = 0; if (cmp > 0) cmp = 1; /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */ if (cmp) NTL_MPN(sub)(cdata, adata, sa, bdata, sb); else NTL_MPN(sub)(cdata, bdata, sb, adata, sa); /* sa == sb */ STRIP(sc, cdata); if (aneg == cmp) sc = -sc; SIZE(c) = sc; } } } void _ntl_gsadd(_ntl_gbigint a, long b, _ntl_gbigint *cc) { if (b == 0) { _ntl_gcopy(a, cc); return; } _ntl_limb_t abs_b = ABS(b); if (XCLIP(abs_b)) { GRegister(xb); _ntl_gintoz(b,&xb); _ntl_gadd(a, xb, cc); return; } long bneg = b < 0; if (ZEROP(a)) { if (!*cc) _ntl_gsetlength(cc, 1); SIZE(*cc) = 1 - 2*bneg; DATA(*cc)[0] = abs_b; return; } long sa, aneg; GET_SIZE_NEG(sa, aneg, a); if (aneg == bneg) { // signs equal: addition if (a == *cc) { // a aliases c _ntl_limb_t *adata = DATA(a); _ntl_limb_t carry = NTL_MPN(add_1)(adata, adata, sa, abs_b); if (carry) { if (MustAlloc(a, sa+1)) { _ntl_gsetlength(cc, sa+1); a = *cc; adata = DATA(a); } adata[sa] = 1; sa++; if (aneg) sa = -sa; SIZE(a) = sa; } } else { // a and c do not alias if (MustAlloc(*cc, sa+1)) _ntl_gsetlength(cc, sa+1); _ntl_limb_t *adata = DATA(a); _ntl_limb_t *cdata = DATA(*cc); _ntl_limb_t carry = NTL_MPN(add_1)(cdata, adata, sa, abs_b); if (carry) { cdata[sa] = 1; sa++; } if (aneg) sa = -sa; SIZE(*cc) = sa; } } else { // opposite sign: subtraction if (sa == 1) { _ntl_limb_t abs_a = DATA(a)[0]; if (abs_a == abs_b) _ntl_gzero(cc); else if (abs_a > abs_b) { if (MustAlloc(*cc, 1)) _ntl_gsetlength(cc, 1); DATA(*cc)[0] = abs_a - abs_b; SIZE(*cc) = 1-2*aneg; } else { if (MustAlloc(*cc, 1)) _ntl_gsetlength(cc, 1); DATA(*cc)[0] = abs_b - abs_a; SIZE(*cc) = -1+2*aneg; } } else { if (MustAlloc(*cc, sa)) _ntl_gsetlength(cc, sa); _ntl_limb_t *adata = DATA(a); _ntl_limb_t *cdata = DATA(*cc); NTL_MPN(sub_1)(cdata, adata, sa, abs_b); if (cdata[sa-1] == 0) sa--; if (aneg) sa = -sa; SIZE(*cc) = sa; } } } void _ntl_gssub(_ntl_gbigint a, long b, _ntl_gbigint *cc) { if (b == 0) { _ntl_gcopy(a, cc); return; } _ntl_limb_t abs_b = ABS(b); if (XCLIP(abs_b)) { GRegister(xb); _ntl_gintoz(b,&xb); _ntl_gsub(a, xb, cc); return; } // the rest of this routine is precisely the same // as gsadd, except for the following line, // which has the sense of the test reversed long bneg = b >= 0; if (ZEROP(a)) { if (!*cc) _ntl_gsetlength(cc, 1); SIZE(*cc) = 1 - 2*bneg; DATA(*cc)[0] = abs_b; return; } long sa, aneg; GET_SIZE_NEG(sa, aneg, a); if (aneg == bneg) { // signs equal: addition if (a == *cc) { // a aliases c _ntl_limb_t *adata = DATA(a); _ntl_limb_t carry = NTL_MPN(add_1)(adata, adata, sa, abs_b); if (carry) { if (MustAlloc(a, sa+1)) { _ntl_gsetlength(cc, sa+1); a = *cc; adata = DATA(a); } adata[sa] = 1; sa++; if (aneg) sa = -sa; SIZE(a) = sa; } } else { // a and c do not alias if (MustAlloc(*cc, sa+1)) _ntl_gsetlength(cc, sa+1); _ntl_limb_t *adata = DATA(a); _ntl_limb_t *cdata = DATA(*cc); _ntl_limb_t carry = NTL_MPN(add_1)(cdata, adata, sa, abs_b); if (carry) { cdata[sa] = 1; sa++; } if (aneg) sa = -sa; SIZE(*cc) = sa; } } else { // opposite sign: subtraction if (sa == 1) { _ntl_limb_t abs_a = DATA(a)[0]; if (abs_a == abs_b) _ntl_gzero(cc); else if (abs_a > abs_b) { if (MustAlloc(*cc, 1)) _ntl_gsetlength(cc, 1); DATA(*cc)[0] = abs_a - abs_b; SIZE(*cc) = 1-2*aneg; } else { if (MustAlloc(*cc, 1)) _ntl_gsetlength(cc, 1); DATA(*cc)[0] = abs_b - abs_a; SIZE(*cc) = -1+2*aneg; } } else { if (MustAlloc(*cc, sa)) _ntl_gsetlength(cc, sa); _ntl_limb_t *adata = DATA(a); _ntl_limb_t *cdata = DATA(*cc); NTL_MPN(sub_1)(cdata, adata, sa, abs_b); if (cdata[sa-1] == 0) sa--; if (aneg) sa = -sa; SIZE(*cc) = sa; } } } void _ntl_gsub(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, aneg, sb, bneg, sc, cmp, rev; _ntl_limb_t *adata, *bdata, *cdata, carry; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gcopy(b, cc); c = *cc; if (c) SIZE(c) = -SIZE(c); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (sa < sb) { SWAP_BIGINT(a, b); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); rev = 1; } else rev = 0; /* sa >= sb */ c = *cc; a_alias = (a == c); b_alias = (b == c); if (aneg != bneg) { /* opposite sign => addition */ sc = sa + 1; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); carry = NTL_MPN(add)(cdata, adata, sa, bdata, sb); if (carry) cdata[sc-1] = carry; else sc--; if (aneg ^ rev) sc = -sc; SIZE(c) = sc; } else { /* same sign => subtraction */ sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa > sb) cmp = 1; else cmp = NTL_MPN(cmp)(adata, bdata, sa); if (cmp == 0) { SIZE(c) = 0; } else { if (cmp < 0) cmp = 0; if (cmp > 0) cmp = 1; /* abs(a) != abs(b) && (abs(a) > abs(b) <=> cmp) */ if (cmp) NTL_MPN(sub)(cdata, adata, sa, bdata, sb); else NTL_MPN(sub)(cdata, bdata, sb, adata, sa); /* sa == sb */ STRIP(sc, cdata); if ((aneg == cmp) ^ rev) sc = -sc; SIZE(c) = sc; } } } void _ntl_gsubpos(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, sb, sc; _ntl_limb_t *adata, *bdata, *cdata; _ntl_gbigint c; long a_alias, b_alias; if (ZEROP(a)) { _ntl_gzero(cc); return; } if (ZEROP(b)) { _ntl_gcopy(a, cc); return; } sa = SIZE(a); sb = SIZE(b); c = *cc; a_alias = (a == c); b_alias = (b == c); sc = sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); if (a_alias) a = c; if (b_alias) b = c; *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); NTL_MPN(sub)(cdata, adata, sa, bdata, sb); STRIP(sc, cdata); SIZE(c) = sc; } #if 1 // This version is faster for small inputs. // It avoids some overheads incurred only when dealing with // aliased outputs. // It also makes direct calls to lower-level mpn functions // for smaller inputs (and for one limb inputs, it avoids // function calls altogether (usually)). // Speedup: 2.5x 1 limb // 1.4x 2 limb // 1.3x 3 limb static inline _ntl_limb_t base_mul (_ntl_limb_t* rp, const _ntl_limb_t* up, long un, const _ntl_limb_t* vp, long vn) { rp[un] = NTL_MPN(mul_1) (rp, up, un, vp[0]); while (--vn >= 1) { rp += 1, vp += 1; rp[un] = NTL_MPN(addmul_1) (rp, up, un, vp[0]); } return rp[un]; } void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { long sa, aneg, sb, bneg, alias, sc; _ntl_limb_t *adata, *bdata, *cdata, msl; _ntl_gbigint c; if (ZEROP(a) || ZEROP(b)) { _ntl_gzero(cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (a != *cc && b != *cc) { // no aliasing c = *cc; sc = sa + sb; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); *cc = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (adata == bdata) { #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], adata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif { NTL_MPN(sqr)(cdata, adata, sa); msl = cdata[2*sa-1]; } } else { #if 1 if (sa >= sb) { #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], bdata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif if (sa <= 4) msl = base_mul(cdata, adata, sa, bdata, sb); else msl = NTL_MPN(mul)(cdata, adata, sa, bdata, sb); } else { if (sb <= 4) msl = base_mul(cdata, bdata, sb, adata, sa); else msl = NTL_MPN(mul)(cdata, bdata, sb, adata, sa); } #else if (sa >= sb) { msl = NTL_MPN(mul)(cdata, adata, sa, bdata, sb); } else { msl = NTL_MPN(mul)(cdata, bdata, sb, adata, sa); } #endif } if (!msl) sc--; if (aneg != bneg) sc = -sc; SIZE(c) = sc; } else { // aliasing GRegister(mem); c = mem; sc = sa + sb; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); mem = c; } adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (adata == bdata) { #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], adata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif { NTL_MPN(sqr)(cdata, adata, sa); msl = cdata[2*sa-1]; } } else { #if 1 if (sa >= sb) { #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], bdata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif if (sa <= 4) msl = base_mul(cdata, adata, sa, bdata, sb); else msl = NTL_MPN(mul)(cdata, adata, sa, bdata, sb); } else { if (sb <= 4) msl = base_mul(cdata, bdata, sb, adata, sa); else msl = NTL_MPN(mul)(cdata, bdata, sb, adata, sa); } #else if (sa >= sb) { msl = NTL_MPN(mul)(cdata, adata, sa, bdata, sb); } else { msl = NTL_MPN(mul)(cdata, bdata, sb, adata, sa); } #endif } if (!msl) sc--; if (aneg != bneg) sc = -sc; SIZE(c) = sc; _ntl_gcopy(mem, cc); } } #else void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *cc) { GRegister(mem); long sa, aneg, sb, bneg, alias, sc; _ntl_limb_t *adata, *bdata, *cdata, msl; _ntl_gbigint c; if (ZEROP(a) || ZEROP(b)) { _ntl_gzero(cc); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sb, bneg, b); if (a == *cc || b == *cc) { c = mem; alias = 1; } else { c = *cc; alias = 0; } sc = sa + sb; if (MustAlloc(c, sc)) _ntl_gsetlength(&c, sc); if (alias) mem = c; else *cc = c; adata = DATA(a); bdata = DATA(b); cdata = DATA(c); if (sa >= sb) msl = NTL_MPN(mul)(cdata, adata, sa, bdata, sb); else msl = NTL_MPN(mul)(cdata, bdata, sb, adata, sa); if (!msl) sc--; if (aneg != bneg) sc = -sc; SIZE(c) = sc; if (alias) _ntl_gcopy(mem, cc); } #endif void _ntl_gsq(_ntl_gbigint a, _ntl_gbigint *cc) { long sa, aneg, alias, sc; _ntl_limb_t *adata, *cdata, msl; _ntl_gbigint c; if (ZEROP(a)) { _ntl_gzero(cc); return; } GET_SIZE_NEG(sa, aneg, a); if (a != *cc) { // no aliasing c = *cc; sc = sa + sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); *cc = c; } adata = DATA(a); cdata = DATA(c); #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], adata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif { NTL_MPN(sqr)(cdata, adata, sa); msl = cdata[2*sa-1]; } if (!msl) sc--; SIZE(c) = sc; } else { // aliasing GRegister(mem); c = mem; sc = sa + sa; if (MustAlloc(c, sc)) { _ntl_gsetlength(&c, sc); mem = c; } adata = DATA(a); cdata = DATA(c); #if (1 && defined(NTL_VIABLE_LL) && NTL_NAIL_BITS==0) if (sa == 1) { ll_type prod; ll_mul(prod, adata[0], adata[0]); cdata[0] = ll_get_lo(prod); msl = cdata[1] = ll_get_hi(prod); } else #endif { NTL_MPN(sqr)(cdata, adata, sa); msl = cdata[2*sa-1]; } if (!msl) sc--; SIZE(c) = sc; _ntl_gcopy(mem, cc); } } void _ntl_gsmul(_ntl_gbigint a, long d, _ntl_gbigint *bb) { long sa, sb; long anegative, bnegative; _ntl_gbigint b; _ntl_limb_t *adata, *bdata; _ntl_limb_t dd, carry; long a_alias; if (ZEROP(a) || !d) { _ntl_gzero(bb); return; } dd = ABS(d); if (XCLIP(dd)) { GRegister(xd); _ntl_gintoz(d,&xd); _ntl_gmul(a, xd, bb); return; } // we may now assume that |d| fits in one limb GET_SIZE_NEG(sa, anegative, a); bnegative = XOR(anegative, d < 0); sb = sa + 1; b = *bb; a_alias = (a == b); if (MustAlloc(b, sb)) { _ntl_gsetlength(&b, sb); if (a_alias) a = b; *bb = b; } adata = DATA(a); bdata = DATA(b); if (dd == 2) carry = NTL_MPN(lshift)(bdata, adata, sa, 1); else carry = NTL_MPN(mul_1)(bdata, adata, sa, dd); if (carry) bdata[sa] = carry; else sb--; if (bnegative) sb = -sb; SIZE(b) = sb; } long _ntl_gsdiv(_ntl_gbigint a, long d, _ntl_gbigint *bb) { long sa, aneg, sb, dneg; _ntl_gbigint b; _ntl_limb_t dd, *adata, *bdata; long r; if (!d) { ArithmeticError("division by zero in _ntl_gsdiv"); } if (ZEROP(a)) { _ntl_gzero(bb); return (0); } dd = ABS(d); if (XCLIP(dd)) { GRegister(xd); GRegister(xr); _ntl_gintoz(d,&xd); _ntl_gdiv(a, xd, bb, &xr); return _ntl_gtoint(xr); } // we may now assume that |d| fits in one limb GET_SIZE_NEG(sa, aneg, a); dneg = d < 0; sb = sa; b = *bb; if (MustAlloc(b, sb)) { /* if b aliases a, then b won't move */ _ntl_gsetlength(&b, sb); *bb = b; } adata = DATA(a); bdata = DATA(b); if (dd == 2) r = NTL_MPN(rshift)(bdata, adata, sa, 1) >> (NTL_ZZ_NBITS - 1); else r = NTL_MPN(divmod_1)(bdata, adata, sa, dd); if (bdata[sb-1] == 0) sb--; SIZE(b) = sb; if (aneg || dneg) { if (aneg != dneg) { if (!r) { SIZE(b) = -SIZE(b); } else { _ntl_gsadd(b, 1, &b); SIZE(b) = -SIZE(b); if (dneg) r = r + d; else r = d - r; *bb = b; } } else r = -r; } return r; } long _ntl_gsmod(_ntl_gbigint a, long d) { long sa, aneg, dneg; _ntl_limb_t dd, *adata; long r; if (!d) { ArithmeticError("division by zero in _ntl_gsmod"); } if (ZEROP(a)) { return (0); } dd = ABS(d); if (XCLIP(dd)) { GRegister(xd); GRegister(xr); _ntl_gintoz(d,&xd); _ntl_gmod(a, xd, &xr); return _ntl_gtoint(xr); } // we may now assume that |d| fits in one limb GET_SIZE_NEG(sa, aneg, a); dneg = d < 0; adata = DATA(a); if (dd == 2) r = adata[0] & 1; else r = NTL_MPN(mod_1)(adata, sa, dd); if (aneg || dneg) { if (aneg != dneg) { if (r) { if (dneg) r = r + d; else r = d - r; } } else r = -r; } return r; } void _ntl_gdiv(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *bb, _ntl_gbigint *rr) { GRegister(b); GRegister(rmem); _ntl_gbigint *rp; long sa, aneg, sb, sd, dneg, sr, in_place; _ntl_limb_t *adata, *ddata, *bdata, *rdata; if (ZEROP(d)) { ArithmeticError("division by zero in _ntl_gdiv"); } if (ZEROP(a)) { if (bb) _ntl_gzero(bb); if (rr) _ntl_gzero(rr); return; } GET_SIZE_NEG(sa, aneg, a); GET_SIZE_NEG(sd, dneg, d); if (!aneg && !dneg && rr && *rr != a && *rr != d) { in_place = 1; rp = rr; } else { in_place = 0; rp = &rmem; } if (sa < sd) { _ntl_gzero(&b); _ntl_gcopy(a, rp); if (aneg) SIZE(*rp) = -SIZE(*rp); goto done; } sb = sa-sd+1; if (MustAlloc(b, sb)) _ntl_gsetlength(&b, sb); sr = sd; if (MustAlloc(*rp, sr)) _ntl_gsetlength(rp, sr); adata = DATA(a); ddata = DATA(d); bdata = DATA(b); rdata = DATA(*rp); NTL_MPN(tdiv_qr)(bdata, rdata, 0, adata, sa, ddata, sd); if (bdata[sb-1] == 0) sb--; SIZE(b) = sb; STRIP(sr, rdata); SIZE(*rp) = sr; done: if (aneg || dneg) { if (aneg != dneg) { if (ZEROP(*rp)) { SIZE(b) = -SIZE(b); } else { if (bb) { _ntl_gsadd(b, 1, &b); SIZE(b) = -SIZE(b); } if (rr) { if (dneg) _ntl_gadd(*rp, d, rp); else _ntl_gsub(d, *rp, rp); } } } else SIZE(*rp) = -SIZE(*rp); } if (bb) _ntl_gcopy(b, bb); if (rr && !in_place) _ntl_gcopy(*rp, rr); } /* a simplified mod operation: assumes a >= 0, d > 0 are non-negative, * that space for the result has already been allocated, * and that inputs do not alias output. */ static void gmod_simple(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr) { GRegister(b); long sa, sb, sd, sr; _ntl_limb_t *adata, *ddata, *bdata, *rdata; _ntl_gbigint r; if (ZEROP(a)) { _ntl_gzero(rr); return; } sa = SIZE(a); sd = SIZE(d); if (sa < sd) { _ntl_gcopy(a, rr); return; } sb = sa-sd+1; if (MustAlloc(b, sb)) _ntl_gsetlength(&b, sb); sr = sd; r = *rr; adata = DATA(a); ddata = DATA(d); bdata = DATA(b); rdata = DATA(r); NTL_MPN(tdiv_qr)(bdata, rdata, 0, adata, sa, ddata, sd); STRIP(sr, rdata); SIZE(r) = sr; } void _ntl_gmod(_ntl_gbigint a, _ntl_gbigint d, _ntl_gbigint *rr) { _ntl_gdiv(a, d, 0, rr); } void _ntl_gquickmod(_ntl_gbigint *rr, _ntl_gbigint d) { _ntl_gdiv(*rr, d, 0, rr); } #if (defined(NTL_GMP_LIP) && (NTL_ZZ_NBITS >= NTL_BITS_PER_LONG)) long _ntl_gsqrts(long n) { _ntl_limb_t ndata, rdata; if (n == 0) { return 0; } if (n < 0) ArithmeticError("negative argument to _ntl_sqrts"); ndata = n; NTL_MPN(sqrtrem)(&rdata, 0, &ndata, 1); return rdata; } #else long _ntl_gsqrts(long n) { if (n < 0) ArithmeticError("_ntl_gsqrts: negative argument"); if (n <= 0) return (0); if (n <= 3) return (1); if (n <= 8) return (2); if (n >= NTL_WSP_BOUND) { GRegister(xn); GRegister(xr); _ntl_gintoz(n,&xn); _ntl_gsqrt(xn,&xr); return _ntl_gtoint(xr); } long a; long ndiva; long newa; newa = 3L << (2 * ((NTL_WSP_NBITS/2) - 1)); // DIRT: here we use the assumption that NTL_WSP_NBITS is // even --- this logic comes from Lenstra's LIP, and I don't know // what happens if it is odd a = 1L << (NTL_WSP_NBITS/2); while (!(n & newa)) { newa >>= 2; a >>= 1; } while (1) { newa = ((ndiva = n / a) + a) / 2; if (newa - ndiva <= 1) { if (newa * newa <= n) return newa; else return ndiva; } a = newa; } } #endif #ifdef NTL_GMP_LIP void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *rr) { GRegister(r); long sn, sr; _ntl_limb_t *ndata, *rdata; if (ZEROP(n)) { _ntl_gzero(rr); return; } sn = SIZE(n); if (sn < 0) ArithmeticError("negative argument to _ntl_gsqrt"); sr = (sn+1)/2; _ntl_gsetlength(&r, sr); ndata = DATA(n); rdata = DATA(r); mpn_sqrtrem(rdata, 0, ndata, sn); STRIP(sr, rdata); SIZE(r) = sr; _ntl_gcopy(r, rr); } #else void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *rr) { GRegister(a); GRegister(ndiva); GRegister(diff); GRegister(r); if (ZEROP(n)) { _ntl_gzero(rr); return; } long sn = SIZE(n); if (sn < 0) ArithmeticError("negative argument to _ntl_gsqrt"); _ntl_limb_t *ndata = DATA(n); if (sn == 1) { _ntl_gintoz(_ntl_gsqrts(ndata[0]), rr); return; } _ntl_gsetlength(&a, sn); _ntl_gsetlength(&ndiva, sn); _ntl_gsetlength(&diff, sn); long sa = (sn+1)/2; _ntl_limb_t *adata = DATA(a); adata[sa-1] = _ntl_gsqrts(ndata[sn-1]) + 1; if (!(sn & 1)) adata[sa-1] <<= (NTL_ZZ_NBITS/2); // DIRT: here we use the assumption that NTL_ZZ_NBITS is // even --- this logic comes from Lenstra's LIP, and I don't know // what happens if it is odd if (adata[sa-1] & NTL_ZZ_RADIX) { sa++; adata[sa-1] = 1; } for (long i = 0; i < sa-1; i++) adata[i] = 0; SIZE(a) = sa; while (1) { _ntl_gdiv(n, a, &ndiva, &r); _ntl_gadd(a, ndiva, &r); _ntl_grshift(r, 1, &r); if (_ntl_gcompare(r, ndiva) <= 0) goto done; _ntl_gsubpos(r, ndiva, &diff); if (ZEROP(diff) || ONEP(diff)) { _ntl_gsq(r, &diff); if (_ntl_gcompare(diff, n) > 0) _ntl_gcopy(ndiva, &r); goto done; } _ntl_gcopy(r, &a); } done: _ntl_gcopy(r, rr); } #endif #ifdef NTL_GMP_LIP void _ntl_ggcd(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r) { GRegister(s1); GRegister(s2); GRegister(res); long k1, k2, k_min, l1, l2, ss1, ss2, sres; _ntl_gcopy(m1, &s1); _ntl_gabs(&s1); _ntl_gcopy(m2, &s2); _ntl_gabs(&s2); if (ZEROP(s1)) { _ntl_gcopy(s2, r); return; } if (ZEROP(s2)) { _ntl_gcopy(s1, r); return; } k1 = _ntl_gmakeodd(&s1); k2 = _ntl_gmakeodd(&s2); if (k1 <= k2) k_min = k1; else k_min = k2; l1 = _ntl_g2log(s1); l2 = _ntl_g2log(s2); ss1 = SIZE(s1); ss2 = SIZE(s2); if (ss1 >= ss2) sres = ss1; else sres = ss2; /* set to max: gmp documentation is unclear on this point */ _ntl_gsetlength(&res, sres); // NOTE: older versions of GMP require first operand has // at least as many bits as the second. // It seems this requirement has been relaxed in more // recent versions. if (l1 >= l2) SIZE(res) = mpn_gcd(DATA(res), DATA(s1), ss1, DATA(s2), ss2); else SIZE(res) = mpn_gcd(DATA(res), DATA(s2), ss2, DATA(s1), ss1); _ntl_glshift(res, k_min, &res); _ntl_gcopy(res, r); } void _ntl_ggcd_alt(_ntl_gbigint mm1, _ntl_gbigint mm2, _ntl_gbigint *rres) { _ntl_ggcd(mm1, mm2, rres); } #else // Interestingly, the Lehmer code even for basic GCD // about twice as fast as the binary gcd static void gxxeucl_basic( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *uu ) { GRegister(a); GRegister(n); GRegister(q); GRegister(x); GRegister(y); GRegister(z); long diff; long ilo; long sa; long sn; long temp; long e; long fast; long parity; long gotthem; _ntl_limb_t *p; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; if (SIZE(ain) < SIZE(nin)) { _ntl_swap(ain, nin); } e = SIZE(ain)+2; _ntl_gsetlength(&a, e); _ntl_gsetlength(&n, e); _ntl_gsetlength(&q, e); _ntl_gsetlength(&x, e); _ntl_gsetlength(&y, e); _ntl_gsetlength(&z, e); fhi1 = double(1L) + double(32L)/NTL_FDOUBLE_PRECISION; flo1 = double(1L) - double(32L)/NTL_FDOUBLE_PRECISION; fhi = double(1L) + double(8L)/NTL_FDOUBLE_PRECISION; flo = double(1L) - double(8L)/NTL_FDOUBLE_PRECISION; _ntl_gcopy(ain, &a); _ntl_gcopy(nin, &n); while (SIZE(n) > 0) { gotthem = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = DBL(*p) * NTL_ZZ_FRADIX; if (sa > 1) num += DBL(*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += DBL(*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = DBL(*p) * NTL_ZZ_FRADIX; if (sn > 1) den += DBL(*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += DBL(*(p - 1)); hi = fhi1 * (num + double(1L)) / den; lo = flo1 * num / (den + double(1L)); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_NSP_BOUND) fast = 0; else { ilo = (long)lo; dirt = hi - double(ilo); if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-double(ilo); lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = double(NTL_NSP_BOUND); temp = try11; try11 = try21; if ((NTL_WSP_BOUND - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_WSP_BOUND - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_gsmul(a, got11, &x); _ntl_gsmul(n, got12, &y); _ntl_gsmul(a, got21, &z); _ntl_gsmul(n, got22, &n); _ntl_gsub(x, y, &a); _ntl_gsub(n, z, &n); } else { _ntl_gdiv(a, n, &q, &a); if (!ZEROP(a)) { _ntl_gdiv(n, a, &q, &n); } else { _ntl_gcopy(n, &a); _ntl_gzero(&n); } } } _ntl_gcopy(a, uu); return; } void _ntl_ggcd(_ntl_gbigint mm1, _ntl_gbigint mm2, _ntl_gbigint *rres) { GRegister(a); GRegister(b); GRegister(inv); if (ZEROP(mm1)) { _ntl_gcopy(mm2, rres); _ntl_gabs(rres); return; } if (ZEROP(mm2)) { _ntl_gcopy(mm1, rres); _ntl_gabs(rres); return; } _ntl_gcopy(mm1, &a); _ntl_gabs(&a); _ntl_gcopy(mm2, &b); _ntl_gabs(&b); gxxeucl_basic(a, b, rres); } // This is the binary gcd algorithm void _ntl_ggcd_alt(_ntl_gbigint mm1, _ntl_gbigint mm2, _ntl_gbigint *rres) { GRegister(a); GRegister(b); GRegister(c); long agrb; long shibl; if (ZEROP(mm1)) { _ntl_gcopy(mm2, rres); _ntl_gabs(rres); return; } if (ZEROP(mm2)) { _ntl_gcopy(mm1, rres); _ntl_gabs(rres); return; } if (mm1 == mm2) { _ntl_gcopy(mm1, rres); _ntl_gabs(rres); return; } long s1 = SIZE(mm1); if (s1 < 0) s1 = -s1; long s2 = SIZE(mm2); if (s2 < 0) s2 = -s2; long maxs1s2 = max(s1, s2); _ntl_gsetlength(&a, maxs1s2); _ntl_gsetlength(&b, maxs1s2); _ntl_gsetlength(&c, maxs1s2); if (s1 != s2) { if (s1 > s2) { _ntl_gcopy(mm2, &a); _ntl_gabs(&a); _ntl_gcopy(mm1, &c); _ntl_gabs(&c); _ntl_gmod(c, a, &b); } else { _ntl_gcopy(mm1, &a); _ntl_gabs(&a); _ntl_gcopy(mm2, &c); _ntl_gabs(&c); _ntl_gmod(c, a, &b); } if (ZEROP(b)) goto done; } else { _ntl_gcopy(mm1, &a); _ntl_gabs(&a); _ntl_gcopy(mm2, &b); _ntl_gabs(&b); } if ((agrb = _ntl_gmakeodd(&a)) < (shibl = _ntl_gmakeodd(&b))) shibl = agrb; if (!(agrb = _ntl_gcompare(a, b))) goto endshift; if (agrb < 0) { _ntl_swap(a, b); } _ntl_gsubpos(a, b, &c); do { _ntl_gmakeodd(&c); if (!(agrb = _ntl_gcompare(b, c))) { _ntl_swap(a, b); goto endshift; } if (agrb > 0) { // (a, b, c) = (b, c, a) _ntl_swap(a, b); _ntl_swap(b, c); } else { // (a, b, c) = (c, b, a) _ntl_swap(a, c); } _ntl_gsubpos(a, b, &c); } while (!ZEROP(c)); endshift: _ntl_glshift(a, shibl, &a); done: _ntl_gcopy(a, rres); } #endif #ifdef NTL_GMP_LIP void _ntl_gexteucl( _ntl_gbigint ain, _ntl_gbigint *xap, _ntl_gbigint bin, _ntl_gbigint *xbp, _ntl_gbigint *dp ) { if (ZEROP(bin)) { long asign = _ntl_gsign(ain); _ntl_gcopy(ain, dp); _ntl_gabs(dp); _ntl_gintoz( (asign >= 0 ? 1 : -1), xap); _ntl_gzero(xbp); } else if (ZEROP(ain)) { long bsign = _ntl_gsign(bin); _ntl_gcopy(bin, dp); _ntl_gabs(dp); _ntl_gzero(xap); _ntl_gintoz(bsign, xbp); } else { GRegister(a); GRegister(b); GRegister(xa); GRegister(xb); GRegister(d); GRegister(tmp); long sa, aneg, sb, bneg, rev; _ntl_limb_t *adata, *bdata, *ddata, *xadata; mp_size_t sxa, sd; GET_SIZE_NEG(sa, aneg, ain); GET_SIZE_NEG(sb, bneg, bin); _ntl_gsetlength(&a, sa+1); /* +1 because mpn_gcdext may need it */ _ntl_gcopy(ain, &a); _ntl_gsetlength(&b, sb+1); /* +1 because mpn_gcdext may need it */ _ntl_gcopy(bin, &b); adata = DATA(a); bdata = DATA(b); if (sa < sb || (sa == sb && NTL_MPN(cmp)(adata, bdata, sa) < 0)) { SWAP_BIGINT(ain, bin); SWAP_LONG(sa, sb); SWAP_LONG(aneg, bneg); SWAP_LIMB_PTR(adata, bdata); rev = 1; } else rev = 0; _ntl_gsetlength(&d, sa+1); /* +1 because mpn_gcdext may need it... documentation is unclear, but this is what is done in mpz_gcdext */ _ntl_gsetlength(&xa, sa+1); /* ditto */ ddata = DATA(d); xadata = DATA(xa); sd = mpn_gcdext(ddata, xadata, &sxa, adata, sa, bdata, sb); SIZE(d) = sd; SIZE(xa) = sxa; #if 0 // since we're now requiring GMP version 5.0.0 or later, // these workarounds are no longer required /* These two ForceNormal's are work-arounds for GMP bugs in GMP 4.3.0 */ ForceNormal(d); ForceNormal(xa); /* now we normalize xa, so that so that xa in ( -b/2d, b/2d ], which makes the output agree with Euclid's algorithm, regardless of what mpn_gcdext does */ if (!ZEROP(xa)) { _ntl_gcopy(bin, &b); SIZE(b) = sb; if (!ONEP(d)) { _ntl_gdiv(b, d, &b, &tmp); if (!ZEROP(tmp)) TerminalError("internal bug in _ntl_gexteucl"); } if (SIZE(xa) > 0) { /* xa positive */ if (_ntl_gcompare(xa, b) > 0) { _ntl_gmod(xa, b, &xa); } _ntl_glshift(xa, 1, &tmp); if (_ntl_gcompare(tmp, b) > 0) { _ntl_gsub(xa, b, &xa); } } else { /* xa negative */ SIZE(xa) = -SIZE(xa); if (_ntl_gcompare(xa, b) > 0) { SIZE(xa) = -SIZE(xa); _ntl_gmod(xa, b, &xa); _ntl_gsub(xa, b, &xa); } else { SIZE(xa) = -SIZE(xa); } _ntl_glshift(xa, 1, &tmp); SIZE(tmp) = -SIZE(tmp); if (_ntl_gcompare(tmp, b) >= 0) { _ntl_gadd(xa, b, &xa); } } } /* end normalize */ #endif if (aneg) _ntl_gnegate(&xa); _ntl_gmul(ain, xa, &tmp); _ntl_gsub(d, tmp, &tmp); _ntl_gdiv(tmp, bin, &xb, &tmp); if (!ZEROP(tmp)) TerminalError("internal bug in _ntl_gexteucl"); if (rev) SWAP_BIGINT(xa, xb); _ntl_gcopy(xa, xap); _ntl_gcopy(xb, xbp); _ntl_gcopy(d, dp); } } long _ntl_ginv(_ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv) { GRegister(u); GRegister(d); GRegister(a); GRegister(n); long sz; long sd; mp_size_t su; if (_ntl_gscompare(nin, 1) <= 0) { LogicError("InvMod: second input <= 1"); } if (_ntl_gsign(ain) < 0) { LogicError("InvMod: first input negative"); } if (_ntl_gcompare(ain, nin) >= 0) { LogicError("InvMod: first input too big"); } sz = SIZE(nin) + 2; if (MustAlloc(a, sz)) _ntl_gsetlength(&a, sz); if (MustAlloc(n, sz)) _ntl_gsetlength(&n, sz); if (MustAlloc(d, sz)) _ntl_gsetlength(&d, sz); if (MustAlloc(u, sz)) _ntl_gsetlength(&u, sz); _ntl_gadd(ain, nin, &a); _ntl_gcopy(nin, &n); /* We apply mpn_gcdext to (a, n) = (ain+nin, nin), because that function * only computes the co-factor of the larger input. This way, we avoid * a multiplication and a division. */ sd = mpn_gcdext(DATA(d), DATA(u), &su, DATA(a), SIZE(a), DATA(n), SIZE(n)); SIZE(d) = sd; SIZE(u) = su; #if 0 // since we're now requiring GMP version 5.0.0 or later, // these workarounds are no longer required /* Thes two ForceNormal's are work-arounds for GMP bugs in GMP 4.3.0 */ ForceNormal(d); ForceNormal(u); #endif if (ONEP(d)) { /* * We make sure that u is in range 0..n-1, just in case * GMP is sloppy. */ #if 0 // since we're now requiring GMP version 5.0.0 or later, // these workarounds are no longer required if (_ntl_gsign(u) < 0) { _ntl_gadd(u, nin, &u); if (_ntl_gsign(u) < 0) { _ntl_gmod(u, nin, &u); } } else if (_ntl_gcompare(u, nin) >= 0) { _ntl_gsub(u, nin, &u); if (_ntl_gcompare(u, nin) >= 0) { _ntl_gmod(u, nin, &u); } } #else if (_ntl_gsign(u) < 0) { _ntl_gadd(u, nin, &u); } #endif _ntl_gcopy(u, invv); return 0; } else { _ntl_gcopy(d, invv); return 1; } } #else static long gxxeucl( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv, _ntl_gbigint *uu ) { GRegister(a); GRegister(n); GRegister(q); GRegister(w); GRegister(x); GRegister(y); GRegister(z); GRegister(inv); long diff; long ilo; long sa; long sn; long temp; long e; long fast; long parity; long gotthem; _ntl_limb_t *p; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; _ntl_gsetlength(&a, (e = 2 + (SIZE(ain) > SIZE(nin) ? SIZE(ain) : SIZE(nin)))); _ntl_gsetlength(&n, e); _ntl_gsetlength(&q, e); _ntl_gsetlength(&w, e); _ntl_gsetlength(&x, e); _ntl_gsetlength(&y, e); _ntl_gsetlength(&z, e); _ntl_gsetlength(&inv, e); fhi1 = double(1L) + double(32L)/NTL_FDOUBLE_PRECISION; flo1 = double(1L) - double(32L)/NTL_FDOUBLE_PRECISION; fhi = double(1L) + double(8L)/NTL_FDOUBLE_PRECISION; flo = double(1L) - double(8L)/NTL_FDOUBLE_PRECISION; _ntl_gcopy(ain, &a); _ntl_gcopy(nin, &n); _ntl_gone(&inv); _ntl_gzero(&w); while (SIZE(n) > 0) { gotthem = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = DBL(*p) * NTL_ZZ_FRADIX; if (sa > 1) num += DBL(*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += DBL(*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = DBL(*p) * NTL_ZZ_FRADIX; if (sn > 1) den += DBL(*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += DBL(*(p - 1)); hi = fhi1 * (num + double(1L)) / den; lo = flo1 * num / (den + double(1L)); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_NSP_BOUND) fast = 0; else { ilo = (long)lo; dirt = hi - double(ilo); if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-double(ilo); lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = double(NTL_NSP_BOUND); temp = try11; try11 = try21; if ((NTL_WSP_BOUND - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_WSP_BOUND - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_gsmul(inv, got11, &x); _ntl_gsmul(w, got12, &y); _ntl_gsmul(inv, got21, &z); _ntl_gsmul(w, got22, &w); _ntl_gadd(x, y, &inv); _ntl_gadd(z, w, &w); _ntl_gsmul(a, got11, &x); _ntl_gsmul(n, got12, &y); _ntl_gsmul(a, got21, &z); _ntl_gsmul(n, got22, &n); _ntl_gsub(x, y, &a); _ntl_gsub(n, z, &n); } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gadd(inv, x, &inv); if (!ZEROP(a)) { _ntl_gdiv(n, a, &q, &n); _ntl_gmul(q, inv, &x); _ntl_gadd(w, x, &w); } else { _ntl_gcopy(n, &a); _ntl_gzero(&n); _ntl_gcopy(w, &inv); _ntl_gnegate(&inv); } } } if (_ntl_gscompare(a, 1) == 0) e = 0; else e = 1; _ntl_gcopy(a, uu); _ntl_gcopy(inv, invv); return (e); } void _ntl_gexteucl( _ntl_gbigint aa, _ntl_gbigint *xa, _ntl_gbigint bb, _ntl_gbigint *xb, _ntl_gbigint *d ) { GRegister(modcon); GRegister(a); GRegister(b); long anegative = 0; long bnegative = 0; _ntl_gcopy(aa, &a); _ntl_gcopy(bb, &b); if (a && SIZE(a) < 0) { anegative = 1; SIZE(a) = -SIZE(a); } else anegative = 0; if (b && SIZE(b) < 0) { bnegative = 1; SIZE(b) = -SIZE(b); } else bnegative = 0; if (ZEROP(b)) { _ntl_gone(xa); _ntl_gzero(xb); _ntl_gcopy(a, d); goto done; } if (ZEROP(a)) { _ntl_gzero(xa); _ntl_gone(xb); _ntl_gcopy(b, d); goto done; } gxxeucl(a, b, xa, d); _ntl_gmul(a, *xa, xb); _ntl_gsub(*d, *xb, xb); _ntl_gdiv(*xb, b, xb, &modcon); if (!ZEROP(modcon)) { TerminalError("non-zero remainder in _ntl_gexteucl BUG"); } done: if (anegative) { _ntl_gnegate(xa); } if (bnegative) { _ntl_gnegate(xb); } } long _ntl_ginv( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint *invv ) { GRegister(u); GRegister(v); long sgn; if (_ntl_gscompare(nin, 1) <= 0) { LogicError("InvMod: second input <= 1"); } sgn = _ntl_gsign(ain); if (sgn < 0) { LogicError("InvMod: first input negative"); } if (_ntl_gcompare(ain, nin) >= 0) { LogicError("InvMod: first input too big"); } if (sgn == 0) { _ntl_gcopy(nin, invv); return 1; } if (!(gxxeucl(ain, nin, &v, &u))) { if (_ntl_gsign(v) < 0) _ntl_gadd(v, nin, &v); _ntl_gcopy(v, invv); return 0; } _ntl_gcopy(u, invv); return 1; } #endif void _ntl_ginvmod( _ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c ) { if (_ntl_ginv(a, n, c)) ArithmeticError("undefined inverse in _ntl_ginvmod"); } void _ntl_gaddmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { if (*c != n) { _ntl_gadd(a, b, c); if (_ntl_gcompare(*c, n) >= 0) _ntl_gsubpos(*c, n, c); } else { GRegister(mem); _ntl_gadd(a, b, &mem); if (_ntl_gcompare(mem, n) >= 0) _ntl_gsubpos(mem, n, c); else _ntl_gcopy(mem, c); } } void _ntl_gsubmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); long cmp; if ((cmp=_ntl_gcompare(a, b)) < 0) { _ntl_gadd(n, a, &mem); _ntl_gsubpos(mem, b, c); } else if (!cmp) _ntl_gzero(c); else _ntl_gsubpos(a, b, c); } void _ntl_gsmulmod( _ntl_gbigint a, long d, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); _ntl_gsmul(a, d, &mem); _ntl_gmod(mem, n, c); } void _ntl_gmulmod( _ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c ) { GRegister(mem); _ntl_gmul(a, b, &mem); _ntl_gmod(mem, n, c); } void _ntl_gsqmod( _ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c ) { _ntl_gmulmod(a, a, n, c); } double _ntl_gdoub_aux(_ntl_gbigint n) { double res; _ntl_limb_t *ndata; long i, sn, nneg; if (!n) return ((double) 0); GET_SIZE_NEG(sn, nneg, n); ndata = DATA(n); res = 0; for (i = sn-1; i >= 0; i--) res = res * NTL_ZZ_FRADIX + DBL(ndata[i]); if (nneg) res = -res; return res; } long _ntl_ground_correction(_ntl_gbigint a, long k, long residual) { long direction; long p; long sgn; long bl; _ntl_limb_t wh; long i; _ntl_limb_t *adata; if (SIZE(a) > 0) sgn = 1; else sgn = -1; adata = DATA(a); p = k - 1; bl = (p/NTL_ZZ_NBITS); wh = ((_ntl_limb_t) 1) << (p - NTL_ZZ_NBITS*bl); if (adata[bl] & wh) { /* bit is 1...we have to see if lower bits are all 0 in order to implement "round to even" */ if (adata[bl] & (wh - ((_ntl_limb_t) 1))) direction = 1; else { i = bl - 1; while (i >= 0 && adata[i] == 0) i--; if (i >= 0) direction = 1; else direction = 0; } /* use residual to break ties */ if (direction == 0 && residual != 0) { if (residual == sgn) direction = 1; else direction = -1; } if (direction == 0) { /* round to even */ wh = CLIP(wh << 1); if (wh == 0) { wh = 1; bl++; } if (adata[bl] & wh) direction = 1; else direction = -1; } } else direction = -1; if (direction == 1) return sgn; return 0; } double _ntl_gdoub(_ntl_gbigint n) { GRegister(tmp); long s; long shamt; long correction; double x; s = _ntl_g2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return _ntl_gdoub_aux(n); _ntl_grshift(n, shamt, &tmp); correction = _ntl_ground_correction(n, shamt, 0); if (correction) _ntl_gsadd(tmp, correction, &tmp); x = _ntl_gdoub_aux(tmp); x = _ntl_ldexp(x, shamt); return x; } double _ntl_glog(_ntl_gbigint n) { GRegister(tmp); static const double log_2 = log(2.0); // GLOBAL (assumes C++11 thread-safe init) long s; long shamt; long correction; double x; if (_ntl_gsign(n) <= 0) ArithmeticError("log argument <= 0"); s = _ntl_g2log(n); shamt = s - NTL_DOUBLE_PRECISION; if (shamt <= 0) return log(_ntl_gdoub_aux(n)); _ntl_grshift(n, shamt, &tmp); correction = _ntl_ground_correction(n, shamt, 0); if (correction) _ntl_gsadd(tmp, correction, &tmp); x = _ntl_gdoub_aux(tmp); return log(x) + shamt*log_2; } void _ntl_gdoubtoz(double a, _ntl_gbigint *xx) { GRegister(x); long neg, i, t, sz; a = floor(a); if (!IsFinite(&a)) ArithmeticError("_ntl_gdoubtoz: attempt to convert non-finite value"); if (a < 0) { a = -a; neg = 1; } else neg = 0; if (a == 0) { _ntl_gzero(xx); return; } sz = 0; while (a >= 1) { a = a*(1.0/double(NTL_NSP_BOUND)); sz++; } i = 0; _ntl_gzero(&x); while (a != 0) { i++; a = a*double(NTL_NSP_BOUND); t = (long) a; a = a - t; // NOTE: this subtraction should be exact if (i == 1) { _ntl_gintoz(t, &x); } else { _ntl_glshift(x, NTL_NSP_NBITS, &x); _ntl_gsadd(x, t, &x); } } if (i > sz) TerminalError("bug in _ntl_gdoubtoz"); _ntl_glshift(x, (sz-i)*NTL_NSP_NBITS, xx); if (neg) _ntl_gnegate(xx); } /* I've adapted LIP's extended euclidean algorithm to * do rational reconstruction. -- VJS. */ long _ntl_gxxratrecon( _ntl_gbigint ain, _ntl_gbigint nin, _ntl_gbigint num_bound, _ntl_gbigint den_bound, _ntl_gbigint *num_out, _ntl_gbigint *den_out ) { GRegister(a); GRegister(n); GRegister(q); GRegister(w); GRegister(x); GRegister(y); GRegister(z); GRegister(inv); GRegister(u); GRegister(a_bak); GRegister(n_bak); GRegister(inv_bak); GRegister(w_bak); _ntl_limb_t *p; long diff; long ilo; long sa; long sn; long snum; long sden; long e; long fast; long temp; long parity; long gotthem; long try11; long try12; long try21; long try22; long got11; long got12; long got21; long got22; double hi; double lo; double dt; double fhi, fhi1; double flo, flo1; double num; double den; double dirt; if (_ntl_gsign(num_bound) < 0) LogicError("rational reconstruction: bad numerator bound"); if (!num_bound) snum = 0; else snum = SIZE(num_bound); if (_ntl_gsign(den_bound) <= 0) LogicError("rational reconstruction: bad denominator bound"); sden = SIZE(den_bound); if (_ntl_gsign(nin) <= 0) LogicError("rational reconstruction: bad modulus"); if (_ntl_gsign(ain) < 0 || _ntl_gcompare(ain, nin) >= 0) LogicError("rational reconstruction: bad residue"); e = 2+SIZE(nin); _ntl_gsetlength(&a, e); _ntl_gsetlength(&n, e); _ntl_gsetlength(&q, e); _ntl_gsetlength(&w, e); _ntl_gsetlength(&x, e); _ntl_gsetlength(&y, e); _ntl_gsetlength(&z, e); _ntl_gsetlength(&inv, e); _ntl_gsetlength(&u, e); _ntl_gsetlength(&a_bak, e); _ntl_gsetlength(&n_bak, e); _ntl_gsetlength(&inv_bak, e); _ntl_gsetlength(&w_bak, e); fhi1 = double(1L) + double(32L)/NTL_FDOUBLE_PRECISION; flo1 = double(1L) - double(32L)/NTL_FDOUBLE_PRECISION; fhi = double(1L) + double(8L)/NTL_FDOUBLE_PRECISION; flo = double(1L) - double(8L)/NTL_FDOUBLE_PRECISION; _ntl_gcopy(ain, &a); _ntl_gcopy(nin, &n); _ntl_gone(&inv); _ntl_gzero(&w); while (1) { if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) break; if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break; _ntl_gcopy(a, &a_bak); _ntl_gcopy(n, &n_bak); _ntl_gcopy(w, &w_bak); _ntl_gcopy(inv, &inv_bak); gotthem = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = DBL(*p) * NTL_ZZ_FRADIX; if (sa > 1) num += DBL(*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += DBL(*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = DBL(*p) * NTL_ZZ_FRADIX; if (sn > 1) den += DBL(*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += DBL(*(p - 1)); hi = fhi1 * (num + double(1L)) / den; lo = flo1 * num / (den + double(1L)); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } try11 = 1; try12 = 0; try21 = 0; try22 = 1; parity = 1; fast = 1; while (fast > 0) { parity = 1 - parity; if (hi >= NTL_NSP_BOUND) fast = 0; else { ilo = (long)lo; dirt = hi - double(ilo); if (dirt < 1.0/NTL_FDOUBLE_PRECISION || !ilo || ilo < (long)hi) fast = 0; else { dt = lo-double(ilo); lo = flo / dirt; if (dt > 1.0/NTL_FDOUBLE_PRECISION) hi = fhi / dt; else hi = double(NTL_NSP_BOUND); temp = try11; try11 = try21; if ((NTL_WSP_BOUND - temp) / ilo < try21) fast = 0; else try21 = temp + ilo * try21; temp = try12; try12 = try22; if ((NTL_WSP_BOUND - temp) / ilo < try22) fast = 0; else try22 = temp + ilo * try22; if ((fast > 0) && (parity > 0)) { gotthem = 1; got11 = try11; got12 = try12; got21 = try21; got22 = try22; } } } } } if (gotthem) { _ntl_gsmul(inv, got11, &x); _ntl_gsmul(w, got12, &y); _ntl_gsmul(inv, got21, &z); _ntl_gsmul(w, got22, &w); _ntl_gadd(x, y, &inv); _ntl_gadd(z, w, &w); _ntl_gsmul(a, got11, &x); _ntl_gsmul(n, got12, &y); _ntl_gsmul(a, got21, &z); _ntl_gsmul(n, got22, &n); _ntl_gsub(x, y, &a); _ntl_gsub(n, z, &n); } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gadd(inv, x, &inv); if (!ZEROP(a)) { _ntl_gdiv(n, a, &q, &n); _ntl_gmul(q, inv, &x); _ntl_gadd(w, x, &w); } else { break; } } } _ntl_gcopy(a_bak, &a); _ntl_gcopy(n_bak, &n); _ntl_gcopy(w_bak, &w); _ntl_gcopy(inv_bak, &inv); _ntl_gnegate(&w); while (1) { sa = SIZE(w); if (sa < 0) SIZE(w) = -sa; if (SIZE(w) >= sden && _ntl_gcompare(w, den_bound) > 0) return 0; SIZE(w) = sa; if (SIZE(n) <= snum && _ntl_gcompare(n, num_bound) <= 0) break; fast = 0; sa = SIZE(a); sn = SIZE(n); diff = sa - sn; if (!diff || diff == 1) { sa = SIZE(a); p = DATA(a) + (sa-1); num = DBL(*p) * NTL_ZZ_FRADIX; if (sa > 1) num += DBL(*(--p)); num *= NTL_ZZ_FRADIX; if (sa > 2) num += DBL(*(p - 1)); sn = SIZE(n); p = DATA(n) + (sn-1); den = DBL(*p) * NTL_ZZ_FRADIX; if (sn > 1) den += DBL(*(--p)); den *= NTL_ZZ_FRADIX; if (sn > 2) den += DBL(*(p - 1)); hi = fhi1 * (num + double(1L)) / den; lo = flo1 * num / (den + double(1L)); if (diff > 0) { hi *= NTL_ZZ_FRADIX; lo *= NTL_ZZ_FRADIX; } if (hi < NTL_NSP_BOUND) { ilo = (long)lo; if (ilo == (long)hi) fast = 1; } } if (fast) { if (ilo != 0) { if (ilo == 1) { _ntl_gsub(inv, w, &inv); _ntl_gsubpos(a, n, &a); } else { _ntl_gsmul(w, ilo, &x); _ntl_gsub(inv, x, &inv); _ntl_gsmul(n, ilo, &x); _ntl_gsubpos(a, x, &a); } } } else { _ntl_gdiv(a, n, &q, &a); _ntl_gmul(q, w, &x); _ntl_gsub(inv, x, &inv); } _ntl_gswap(&a, &n); _ntl_gswap(&inv, &w); } if (_ntl_gsign(w) < 0) { _ntl_gnegate(&w); _ntl_gnegate(&n); } _ntl_gcopy(n, num_out); _ntl_gcopy(w, den_out); return 1; } void _ntl_gexp( _ntl_gbigint a, long e, _ntl_gbigint *bb ) { long k; long len_a; GRegister(res); if (!e) { _ntl_gone(bb); return; } if (e < 0) ArithmeticError("negative exponent in _ntl_gexp"); if (ZEROP(a)) { _ntl_gzero(bb); return; } len_a = _ntl_g2log(a); if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e) ResourceError("overflow in _ntl_gexp"); _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); _ntl_gcopy(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_gsq(res, &res); if (e & k) _ntl_gmul(a, res, &res); } _ntl_gcopy(res, bb); } void _ntl_gexps( long a, long e, _ntl_gbigint *bb ) { long k; long len_a; GRegister(res); if (!e) { _ntl_gone(bb); return; } if (e < 0) ArithmeticError("negative exponent in _ntl_zexps"); if (!a) { _ntl_gzero(bb); return; } len_a = _ntl_g2logs(a); if (len_a > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/e) ResourceError("overflow in _ntl_gexps"); _ntl_gsetlength(&res, (len_a*e+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS); _ntl_gintoz(a, &res); k = 1; while ((k << 1) <= e) k <<= 1; while (k >>= 1) { _ntl_gsq(res, &res); if (e & k) _ntl_gsmul(res, a, &res); } _ntl_gcopy(res, bb); } static long OptWinSize(long n) /* finds k that minimizes n/(k+1) + 2^{k-1} */ { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/((double)(k+2)) + ((double)(1L << k)); if (v_new >= v) break; v = v_new; k++; } return k; } static _ntl_limb_t neg_inv_mod_limb(_ntl_limb_t m0) { _ntl_limb_t x; long k; x = 1; k = 1; while (k < NTL_ZZ_NBITS) { x += x * (1UL - x * m0); k <<= 1; } return CLIP(-x); } /* Montgomery reduction: * This computes res = T/b^m mod N, where b = 2^{NTL_ZZ_NBITS}. * It is assumed that N has n limbs, and that T has at most n + m limbs. * Also, inv should be set to -N^{-1} mod b. * Finally, it is assumed that T has space allocated for n + m limbs, * and that res has space allocated for n limbs. * Note: res should not overlap any inputs, and T is destroyed. * Note: res will have at most n limbs, but may not be fully reduced * mod N. In general, we will have res < T/b^m + N. */ static void redc(_ntl_gbigint T, _ntl_gbigint N, long m, _ntl_limb_t inv, _ntl_gbigint res) { long n, sT, i; _ntl_limb_t *Ndata, *Tdata, *resdata, q, d, t, c; n = SIZE(N); Ndata = DATA(N); sT = SIZE(T); Tdata = DATA(T); resdata = DATA(res); for (i = sT; i < m+n; i++) Tdata[i] = 0; c = 0; for (i = 0; i < m; i++) { q = CLIP(Tdata[i]*inv); d = NTL_MPN(addmul_1)(Tdata+i, Ndata, n, q); // (c, Tdata[i+n]) = c + d + Tdata[i+n] t = CLIP(Tdata[i+n] + d); Tdata[i+n] = CLIP(t + c); if (t < d || (c == 1 && CLIP(t + c) == 0)) c = 1; else c = 0; } if (c) { NTL_MPN(sub_n)(resdata, Tdata + m, Ndata, n); } else { for (i = 0; i < n; i++) resdata[i] = Tdata[m + i]; } i = n; STRIP(i, resdata); SIZE(res) = i; SIZE(T) = 0; } // This montgomery code is for external consumption... // This is currently used in the CRT reconstruction step // for ZZ_pX arithmetic. It gives a nontrivial speedup // for smallish p (up to a few hundred bits) class _ntl_reduce_struct_montgomery : public _ntl_reduce_struct { public: long m; _ntl_limb_t inv; _ntl_gbigint_wrapped N; void eval(_ntl_gbigint *rres, _ntl_gbigint *TT); void adjust(_ntl_gbigint *x); }; void _ntl_reduce_struct_montgomery::eval(_ntl_gbigint *rres, _ntl_gbigint *TT) { long n, sT, i; _ntl_limb_t *Ndata, *Tdata, *resdata, q, d, t, c; _ntl_gbigint res, T; T = *TT; // quick zero test, in case of sparse polynomials if (ZEROP(T)) { _ntl_gzero(rres); return; } n = SIZE(N); Ndata = DATA(N); if (MustAlloc(T, m+n)) { _ntl_gsetlength(&T, m+n); *TT = T; } res = *rres; if (MustAlloc(res, n)) { _ntl_gsetlength(&res, n); *rres = res; } sT = SIZE(T); Tdata = DATA(T); resdata = DATA(res); for (i = sT; i < m+n; i++) Tdata[i] = 0; c = 0; for (i = 0; i < m; i++) { q = CLIP(Tdata[i]*inv); d = NTL_MPN(addmul_1)(Tdata+i, Ndata, n, q); // (c, Tdata[i+n]) = c + d + Tdata[i+n] t = CLIP(Tdata[i+n] + d); Tdata[i+n] = CLIP(t + c); if (t < d || (c == 1 && CLIP(t + c) == 0)) c = 1; else c = 0; } if (c || NTL_MPN(cmp)(Tdata + m, Ndata, n) >= 0) { NTL_MPN(sub_n)(resdata, Tdata + m, Ndata, n); } else { for (i = 0; i < n; i++) resdata[i] = Tdata[m + i]; } i = n; STRIP(i, resdata); SIZE(res) = i; SIZE(T) = 0; } // this will adjust the given number by multiplying by the // montgomery scaling factor void _ntl_reduce_struct_montgomery::adjust(_ntl_gbigint *x) { GRegister(tmp); _ntl_glshift(*x, m*NTL_ZZ_NBITS, &tmp); _ntl_gmod(tmp, N, x); } class _ntl_reduce_struct_plain : public _ntl_reduce_struct { public: _ntl_gbigint_wrapped N; void eval(_ntl_gbigint *rres, _ntl_gbigint *TT) { _ntl_gmod(*TT, N, rres); } void adjust(_ntl_gbigint *x) { } }; // assumption: all values passed to eval for montgomery reduction // are in [0, modulus*excess] _ntl_reduce_struct * _ntl_reduce_struct_build(_ntl_gbigint modulus, _ntl_gbigint excess) { if (_ntl_godd(modulus)) { UniquePtr<_ntl_reduce_struct_montgomery> C; C.make(); C->m = _ntl_gsize(excess); C->inv = neg_inv_mod_limb(DATA(modulus)[0]); _ntl_gcopy(modulus, &C->N); return C.release(); } else { UniquePtr<_ntl_reduce_struct_plain> C; C.make(); _ntl_gcopy(modulus, &C->N); return C.release(); } } #if (defined(NTL_GMP_LIP) && NTL_NAIL_BITS == 0) // DIRT: only works with empty nails // Assumes: F > 1, 0 < g < F, e > 0 struct wrapped_mpz { mpz_t body; wrapped_mpz() { mpz_init(body); } ~wrapped_mpz() { mpz_clear(body); } }; static void _ntl_gmp_powermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h) { wrapped_mpz gg; wrapped_mpz ee; wrapped_mpz FF; wrapped_mpz res; mpz_import(gg.body, SIZE(g), -1, sizeof(mp_limb_t), 0, 0, DATA(g)); mpz_import(ee.body, SIZE(e), -1, sizeof(mp_limb_t), 0, 0, DATA(e)); mpz_import(FF.body, SIZE(F), -1, sizeof(mp_limb_t), 0, 0, DATA(F)); mpz_powm(res.body, gg.body, ee.body, FF.body); if (mpz_sgn(res.body) == 0) { _ntl_gzero(h); return; } long sz = mpz_size(res.body); _ntl_gsetlength(h, sz); _ntl_limb_t *hdata = DATA(*h); SIZE(*h) = sz; mpz_export(hdata, 0, -1, sizeof(mp_limb_t), 0, 0, res.body); } #if 1 // This version avoids memory allocations. // On 2-limb numbers, it is about 10% faster. static void _ntl_gmp_powermod_alt(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h) { NTL_TLS_LOCAL(wrapped_mpz, gg); NTL_TLS_LOCAL(wrapped_mpz, ee); NTL_TLS_LOCAL(wrapped_mpz, FF); NTL_TLS_LOCAL(wrapped_mpz, res); mpz_import(gg.body, SIZE(g), -1, sizeof(mp_limb_t), 0, 0, DATA(g)); mpz_import(ee.body, SIZE(e), -1, sizeof(mp_limb_t), 0, 0, DATA(e)); mpz_import(FF.body, SIZE(F), -1, sizeof(mp_limb_t), 0, 0, DATA(F)); mpz_powm(res.body, gg.body, ee.body, FF.body); if (mpz_sgn(res.body) == 0) { _ntl_gzero(h); return; } long sz = mpz_size(res.body); _ntl_gsetlength(h, sz); _ntl_limb_t *hdata = DATA(*h); SIZE(*h) = sz; mpz_export(hdata, 0, -1, sizeof(mp_limb_t), 0, 0, res.body); } #endif #endif #define REDC_CROSS (32) void _ntl_gpowermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h) /* h = g^e mod f using "sliding window" algorithm remark: the notation (h, g, e, F) is strange, because I copied the code from BB.c. */ { if (_ntl_gsign(e) < 0 || _ntl_gsign(g) < 0 || _ntl_gcompare(g, F) >= 0 || _ntl_gscompare(F, 1) <= 0) { LogicError("PowerMod: bad args"); } if (ZEROP(e)) { _ntl_gone(h); return; } if (ONEP(e)) { _ntl_gcopy(g, h); return; } if (_ntl_gscompare(e, 2) == 0) { _ntl_gsqmod(g, F, h); return; } if (ZEROP(g)) { _ntl_gzero(h); return; } long n = _ntl_g2log(e); #if (1 && defined(NTL_GMP_LIP) && NTL_NAIL_BITS == 0) if (n > 10) { if (SIZE(F) < 6 && SIZE(e) < 10) _ntl_gmp_powermod_alt(g, e, F, h); else _ntl_gmp_powermod(g, e, F, h); return; } #endif _ntl_gbigint_wrapped res, gg, t; UniqueArray<_ntl_gbigint_wrapped> v; long i, k, val, cnt, m; long use_redc, sF; _ntl_limb_t inv; sF = SIZE(F); res = 0; _ntl_gsetlength(&res, sF*2); t = 0; _ntl_gsetlength(&t, sF*2); #ifdef NTL_GMP_LIP // NOTE: GMP has a fast division routine for larger // numbers, so we only use Montgomery for smallish moduli use_redc = (DATA(F)[0] & 1) && sF < REDC_CROSS; #else use_redc = (DATA(F)[0] & 1); #endif gg = 0; if (use_redc) { _ntl_glshift(g, sF*NTL_ZZ_NBITS, &res); _ntl_gmod(res, F, &gg); inv = neg_inv_mod_limb(DATA(F)[0]); } else _ntl_gcopy(g, &gg); if (_ntl_gscompare(g, 2) == 0) { /* plain square-and-multiply algorithm, optimized for g == 2 */ _ntl_gbigint_wrapped F1; if (use_redc) { long shamt; shamt = COUNT_BITS(DATA(F)[sF-1]); shamt = NTL_ZZ_NBITS - shamt; _ntl_glshift(F, shamt, &F1); } _ntl_gcopy(gg, &res); for (i = n - 2; i >= 0; i--) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); if (_ntl_gbit(e, i)) { _ntl_gadd(res, res, &res); if (use_redc) { while (SIZE(res) > sF) { _ntl_gsubpos(res, F1, &res); } } else { if (_ntl_gcompare(res, F) >= 0) _ntl_gsubpos(res, F, &res); } } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } _ntl_gcopy(res, h); return; } if (n < 16) { /* plain square-and-multiply algorithm */ _ntl_gcopy(gg, &res); for (i = n - 2; i >= 0; i--) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); if (_ntl_gbit(e, i)) { _ntl_gmul(res, gg, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } _ntl_gcopy(res, h); return; } k = OptWinSize(n); if (k > 5) k = 5; v.SetLength(1L << (k-1)); for (i = 0; i < (1L << (k-1)); i++) { v[i] = 0; _ntl_gsetlength(&v[i], sF); } _ntl_gcopy(gg, &v[0]); if (k > 1) { _ntl_gsq(gg, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); for (i = 1; i < (1L << (k-1)); i++) { _ntl_gmul(v[i-1], res, &t); if (use_redc) redc(t, F, sF, inv, v[i]); else _ntl_gmod(t, F, &v[i]); } } _ntl_gcopy(gg, &res); val = 0; for (i = n-2; i >= 0; i--) { val = (val << 1) | _ntl_gbit(e, i); if (val == 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); } else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); m = m >> 1; } _ntl_gmul(res, v[val >> 1], &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); while (cnt > 0) { _ntl_gsq(res, &t); if (use_redc) redc(t, F, sF, inv, res); else _ntl_gmod(t, F, &res); cnt--; } val = 0; } } if (use_redc) { _ntl_gcopy(res, &t); redc(t, F, sF, inv, res); if (_ntl_gcompare(res, F) >= 0) { _ntl_gsub(res, F, &res); } } _ntl_gcopy(res, h); } long _ntl_gisone(_ntl_gbigint rep) { return ONEP(rep); } long _ntl_gsptest(_ntl_gbigint rep) { return !rep || SIZE(rep) == 0 || ((SIZE(rep) == 1 || SIZE(rep) == -1) && DATA(rep)[0] < ((_ntl_limb_t) NTL_SP_BOUND)); } long _ntl_gwsptest(_ntl_gbigint rep) { return !rep || SIZE(rep) == 0 || ((SIZE(rep) == 1 || SIZE(rep) == -1) && DATA(rep)[0] < ((_ntl_limb_t) NTL_WSP_BOUND)); } long _ntl_gcrtinrange(_ntl_gbigint g, _ntl_gbigint a) { long sa, sg, i; _ntl_limb_t carry, u, v; _ntl_limb_t *adata, *gdata; if (!a || SIZE(a) <= 0) return 0; sa = SIZE(a); if (!g) return 1; sg = SIZE(g); if (sg == 0) return 1; if (sg < 0) sg = -sg; if (sa-sg > 1) return 1; if (sa-sg < 0) return 0; adata = DATA(a); gdata = DATA(g); carry=0; if (sa-sg == 1) { if (adata[sa-1] > ((_ntl_limb_t) 1)) return 1; carry = 1; } i = sg-1; u = 0; v = 0; while (i >= 0 && u == v) { u = (carry << (NTL_ZZ_NBITS-1)) + (adata[i] >> 1); v = gdata[i]; carry = (adata[i] & 1); i--; } if (u == v) { if (carry) return 1; return (SIZE(g) > 0); } else return (u > v); } #if (NTL_NAIL_BITS == 0) /* DIRT: this routine will not work with non-empty "nails" */ /* and assumes NTL_ZZ_NBITS is a multiple of 8 */ #if (NTL_ZZ_NBITS % 8 != 0) #error "assumption that NTL_ZZ_NBITS % 8 != 0" #endif void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n) { long lw, r, i, j; _ntl_limb_t *xp, t; while (n > 0 && p[n-1] == 0) n--; if (n <= 0) { _ntl_gzero(x); return; } const long BytesPerLimb = NTL_ZZ_NBITS/8; lw = n/BytesPerLimb; r = n - lw*BytesPerLimb; if (r != 0) lw++; else r = BytesPerLimb; _ntl_gsetlength(x, lw); xp = DATA(*x); for (i = 0; i < lw-1; i++) { t = 0; for (j = 0; j < BytesPerLimb; j++) { t >>= 8; t += (((_ntl_limb_t)(*p)) & ((_ntl_limb_t) 255)) << ((BytesPerLimb-1)*8); p++; } xp[i] = t; } t = 0; for (j = 0; j < r; j++) { t >>= 8; t += (((_ntl_limb_t)(*p)) & ((_ntl_limb_t) 255)) << ((BytesPerLimb-1)*8); p++; } t >>= (BytesPerLimb-r)*8; xp[lw-1] = t; // strip not necessary here // STRIP(lw, xp); SIZE(*x) = lw; } void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long n) { long lbits, lbytes, min_bytes, min_words, r; long i, j; _ntl_limb_t *ap, t; if (n < 0) n = 0; const long BytesPerLimb = NTL_ZZ_NBITS/8; lbits = _ntl_g2log(a); lbytes = (lbits+7)/8; min_bytes = (lbytes < n) ? lbytes : n; min_words = min_bytes/BytesPerLimb; r = min_bytes - min_words*BytesPerLimb; if (r != 0) min_words++; else r = BytesPerLimb; if (a) ap = DATA(a); else ap = 0; for (i = 0; i < min_words-1; i++) { t = ap[i]; for (j = 0; j < BytesPerLimb; j++) { *p = t & ((_ntl_limb_t) 255); t >>= 8; p++; } } if (min_words > 0) { t = ap[min_words-1]; for (j = 0; j < r; j++) { *p = t & ((_ntl_limb_t) 255); t >>= 8; p++; } } for (j = min_bytes; j < n; j++) { *p = 0; p++; } } #else void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n) { long sz; long i; _ntl_limb_t *xdata; _ntl_limb_t carry, tmp; long bitpos, wordpos, bitoffset, diff; long nbits; while (n > 0 && p[n-1] == 0) n--; if (n <= 0) { _ntl_gzero(x); return; } if (n > (NTL_MAX_LONG-(NTL_ZZ_NBITS-1))/8) ResourceError("ZZFromBytes: excessive length"); nbits = 0; tmp = p[n-1]; while (tmp) { tmp >>= 1; nbits++; } sz = ((n-1)*8 + nbits + NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS; _ntl_gsetlength(x, sz); xdata = DATA(*x); for (i = 0; i < sz; i++) xdata[i] = 0; carry = 0; for (i = 0; i < n; i++) { bitpos = i*8; wordpos = bitpos/NTL_ZZ_NBITS; bitoffset = bitpos - wordpos*NTL_ZZ_NBITS; diff = NTL_ZZ_NBITS-bitoffset; tmp = _ntl_limb_t(p[i]) & _ntl_limb_t(255); xdata[wordpos] |= carry | CLIP(tmp << bitoffset); carry = tmp >> diff; } xdata[sz-1] |= carry; SIZE(*x) = sz; } void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long nn) { long k = _ntl_g2log(a); long n = (k+7)/8; long sz = _ntl_gsize(a); long min_n = min(n, nn); _ntl_limb_t *ap; long i; if (a) ap = DATA(a); else ap = 0; for (i = 0; i < min_n; i++) { long bitpos = i*8; long wordpos = bitpos/NTL_ZZ_NBITS; long bitoffset = bitpos - wordpos*NTL_ZZ_NBITS; long diff; p[i] = (ap[wordpos] >> bitoffset) & _ntl_limb_t(255); diff = NTL_ZZ_NBITS - bitoffset; if (diff < 8 && wordpos < sz-1) { _ntl_limb_t msk = (_ntl_limb_t(1) << (8-diff))-_ntl_limb_t(1); p[i] |= ((ap[wordpos+1] & msk) << diff); } } for (i = min_n; i < nn; i++) p[i] = 0; } #endif long _ntl_gblock_construct_alloc(_ntl_gbigint *x, long d, long n) { long d1, sz, AllocAmt, m, j, alloc; char *p; _ntl_gbigint t; /* check n value */ if (n <= 0) LogicError("block construct: n must be positive"); /* check d value */ if (d <= 0) LogicError("block construct: d must be positive"); if (NTL_OVERFLOW(d, NTL_ZZ_NBITS, NTL_ZZ_NBITS)) ResourceError("block construct: d too large"); d1 = d + 1; #ifdef NTL_SMALL_MP_SIZE_T /* this makes sure that numbers don't get too big for GMP */ if (d1 >= (1L << (NTL_BITS_PER_INT-4))) ResourceError("size too big for GMP"); #endif if (STORAGE_OVF(d1)) ResourceError("block construct: d too large"); sz = STORAGE(d1); AllocAmt = NTL_MAX_ALLOC_BLOCK/sz; if (AllocAmt == 0) AllocAmt = 1; if (AllocAmt < n) m = AllocAmt; else m = n; p = (char *) NTL_SNS_MALLOC(m, sz, 0); if (!p) MemoryError(); *x = (_ntl_gbigint) p; for (j = 0; j < m; j++) { t = (_ntl_gbigint) p; alloc = (d1 << 2) | 1; if (j < m-1) alloc |= 2; ALLOC(t) = alloc; SIZE(t) = 0; p += sz; } return m; } void _ntl_gblock_construct_set(_ntl_gbigint x, _ntl_gbigint *y, long i) { long d1, sz; d1 = ALLOC(x) >> 2; sz = STORAGE(d1); *y = (_ntl_gbigint) (((char *) x) + i*sz); } long _ntl_gblock_destroy(_ntl_gbigint x) { long d1, sz, alloc, m; char *p; _ntl_gbigint t; d1 = ALLOC(x) >> 2; sz = STORAGE(d1); p = (char *) x; m = 1; for (;;) { t = (_ntl_gbigint) p; alloc = ALLOC(t); // NOTE: this must not throw if ((alloc & 1) == 0) TerminalError("corrupted memory detected in _ntl_gblock_destroy"); if ((alloc & 2) == 0) break; m++; p += sz; } free(x); return m; } long _ntl_gblock_storage(long d) { long d1, sz; d1 = d + 1; sz = STORAGE(d1) + sizeof(_ntl_gbigint); return sz; } static long SpecialPower(long e, long p) { long a; long x, y; a = (long) ((((_ntl_limb_t) 1) << (NTL_ZZ_NBITS-2)) % ((_ntl_limb_t) p)); a = MulMod(a, 2, p); a = MulMod(a, 2, p); x = 1; y = a; while (e) { if (e & 1) x = MulMod(x, y, p); y = MulMod(y, y, p); e = e >> 1; } return x; } static void sp_ext_eucl(long *dd, long *ss, long *tt, long a, long b) { long u, v, u0, v0, u1, v1, u2, v2, q, r; long aneg = 0, bneg = 0; if (a < 0) { if (a < -NTL_MAX_LONG) ResourceError("integer overflow"); a = -a; aneg = 1; } if (b < 0) { if (b < -NTL_MAX_LONG) ResourceError("integer overflow"); b = -b; bneg = 1; } u1=1; v1=0; u2=0; v2=1; u = a; v = b; while (v != 0) { q = u / v; r = u % v; u = v; v = r; u0 = u2; v0 = v2; u2 = u1 - q*u2; v2 = v1- q*v2; u1 = u0; v1 = v0; } if (aneg) u1 = -u1; if (bneg) v1 = -v1; *dd = u; *ss = u1; *tt = v1; } static long sp_inv_mod(long a, long n) { long d, s, t; sp_ext_eucl(&d, &s, &t, a, n); if (d != 1) ArithmeticError("inverse undefined"); if (s < 0) return s + n; else return s; } class _ntl_tmp_vec_crt_fast : public _ntl_tmp_vec { public: UniqueArray<_ntl_gbigint_wrapped> rem_vec; UniqueArray<_ntl_gbigint_wrapped> temps; UniqueArray val_vec; }; class _ntl_crt_struct_basic : public _ntl_crt_struct { public: UniqueArray<_ntl_gbigint_wrapped> v; long sbuf; long n; bool special(); void insert(long i, _ntl_gbigint m); _ntl_tmp_vec *extract(); _ntl_tmp_vec *fetch(); void eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *tmp_vec); }; #if (defined(NTL_TBL_CRT)) class _ntl_crt_struct_tbl : public _ntl_crt_struct { public: Unique2DArray<_ntl_limb_t> v; long n; long sz; bool special(); void insert(long i, _ntl_gbigint m); _ntl_tmp_vec *extract(); _ntl_tmp_vec *fetch(); void eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *tmp_vec); }; #endif class _ntl_crt_struct_fast : public _ntl_crt_struct { public: long n; long levels; UniqueArray primes; UniqueArray inv_vec; UniqueArray index_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec; UniqueArray<_ntl_gbigint_wrapped> coeff_vec; _ntl_gbigint_wrapped modulus; UniquePtr<_ntl_tmp_vec_crt_fast> stored_tmp_vec; bool special(); void insert(long i, _ntl_gbigint m); _ntl_tmp_vec *extract(); _ntl_tmp_vec *fetch(); void eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *tmp_vec); }; #define GCRT_TMPS (2) _ntl_crt_struct * _ntl_crt_struct_build(long n, _ntl_gbigint p, long (*primes)(long)) { #ifdef NTL_GMP_LIP if (n > 800) #else if (0) // NOTE: without GMP, this does not seem to help #endif { UniqueArray q; UniqueArray inv_vec; UniqueArray index_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec, rem_vec, coeff_vec; UniqueArray<_ntl_gbigint_wrapped> temps; long i, j; long levels, vec_len; levels = 0; while ((n >> levels) >= 16) levels++; vec_len = (1L << levels) - 1; temps.SetLength(GCRT_TMPS); rem_vec.SetLength(vec_len); q.SetLength(n); for (i = 0; i < n; i++) q[i] = primes(i); inv_vec.SetLength(n); index_vec.SetLength(vec_len+1); prod_vec.SetLength(vec_len); coeff_vec.SetLength(n); index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsdiv(prod_vec[i], q[j], &coeff_vec[j]); } for (i = (1L << (levels-1)) - 2; i >= 0; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); /*** new asymptotically fast code to compute inv_vec ***/ _ntl_gone(&rem_vec[0]); for (i = 0; i < (1L << (levels-1)) - 1; i++) { _ntl_gmod(rem_vec[i], prod_vec[2*i+1], &temps[0]); _ntl_gmul(temps[0], prod_vec[2*i+2], &temps[1]); _ntl_gmod(temps[1], prod_vec[2*i+1], &rem_vec[2*i+1]); _ntl_gmod(rem_vec[i], prod_vec[2*i+2], &temps[0]); _ntl_gmul(temps[0], prod_vec[2*i+1], &temps[1]); _ntl_gmod(temps[1], prod_vec[2*i+2], &rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) { long tt, tt1, tt2; _ntl_gsdiv(prod_vec[i], q[j], &temps[0]); tt = _ntl_gsmod(temps[0], q[j]); tt1 = _ntl_gsmod(rem_vec[i], q[j]); tt2 = MulMod(tt, tt1, q[j]); inv_vec[j] = sp_inv_mod(tt2, q[j]); } } UniquePtr<_ntl_crt_struct_fast> C; C.make(); C->n = n; C->primes.move(q); C->inv_vec.move(inv_vec); C->levels = levels; C->index_vec.move(index_vec); C->prod_vec.move(prod_vec); C->coeff_vec.move(coeff_vec); _ntl_gcopy(p, &C->modulus); C->stored_tmp_vec.make(); C->stored_tmp_vec->rem_vec.move(rem_vec); C->stored_tmp_vec->temps.move(temps); C->stored_tmp_vec->val_vec.SetLength(n); return C.release(); } #if (defined(NTL_TBL_CRT)) // assert: defined(NTL_CRT_ALTCODE) || defined(NTL_CRT_ALTCODE_SMALL) // we use the alternative CRT code, either unconditionally, // or only for small moduli. #if (!defined(NTL_CRT_ALTCODE)) if (n <= 16) #endif { UniquePtr<_ntl_crt_struct_tbl> C; C.make(); C->n = n; C->sz = SIZE(p); C->v.SetDims(C->sz, C->n); return C.release(); } #endif // as a fallback, we use the basic CRT code { UniquePtr<_ntl_crt_struct_basic> C; C.make(); C->n = n; C->v.SetLength(n); C->sbuf = SIZE(p)+2; return C.release(); } } /* extracts existing tmp_vec, if possible -- read/write operation */ _ntl_tmp_vec *_ntl_crt_struct_basic::extract() { return 0; } #if (defined(NTL_TBL_CRT)) _ntl_tmp_vec *_ntl_crt_struct_tbl::extract() { return 0; } #endif _ntl_tmp_vec *_ntl_crt_struct_fast::extract() { if (stored_tmp_vec) return stored_tmp_vec.release(); else return fetch(); } /* read only operation */ _ntl_tmp_vec *_ntl_crt_struct_basic::fetch() { return 0; } #if (defined(NTL_TBL_CRT)) _ntl_tmp_vec *_ntl_crt_struct_tbl::fetch() { return 0; } #endif _ntl_tmp_vec *_ntl_crt_struct_fast::fetch() { long vec_len = (1L << levels) - 1; UniquePtr<_ntl_tmp_vec_crt_fast> res; res.make(); res->temps.SetLength(GCRT_TMPS); res->rem_vec.SetLength(vec_len); res->val_vec.SetLength(n); return res.release(); } void _ntl_crt_struct_basic::insert(long i, _ntl_gbigint m) { _ntl_gcopy(m, &v[i]); } #if (defined(NTL_TBL_CRT)) void _ntl_crt_struct_tbl::insert(long i, _ntl_gbigint m) { if (i < 0 || i >= n) LogicError("insert: bad args"); if (!m) for (long j = 0; j < sz; j++) v[j][i] = 0; else { long sm = SIZE(m); if (sm < 0 || sm > sz) LogicError("insert: bad args"); const _ntl_limb_t *mdata = DATA(m); for (long j = 0; j < sm; j++) v[j][i] = mdata[j]; for (long j = sm; j < sz; j++) v[j][i] = 0; } } #endif void _ntl_crt_struct_fast::insert(long i, _ntl_gbigint m) { LogicError("insert called improperly"); } void _ntl_crt_struct_basic::eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *generic_tmp_vec) { _ntl_limb_t *xx, *yy; _ntl_gbigint x1; long i, sx; long sy; _ntl_limb_t carry; sx = sbuf; _ntl_gsetlength(x, sx); x1 = *x; xx = DATA(x1); for (i = 0; i < sx; i++) xx[i] = 0; for (i = 0; i < n; i++) { if (!v[i]) continue; yy = DATA(v[i]); sy = SIZE(v[i]); if (!sy || !b[i]) continue; carry = NTL_MPN(addmul_1)(xx, yy, sy, b[i]); yy = xx + sy; *yy = CLIP(*yy + carry); if (*yy < carry) { /* unsigned comparison! */ do { yy++; *yy = CLIP(*yy + 1); } while (*yy == 0); } } STRIP(sx, xx); SIZE(x1) = sx; } #if (defined(NTL_TBL_CRT)) #define CRT_ALTCODE_UNROLL (1) void _ntl_crt_struct_tbl::eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *generic_tmp_vec) { long sx; _ntl_gbigint x1; long i, j; // quick test for zero vector // most likely, they are either all zero (if we are working // with some sparse polynomials) or none of them are zero, // so in the general case, this should go fast if (!b[0]) { i = 1; while (i < n && !b[i]) i++; if (i >= n) { _ntl_gzero(x); return; } } sx = sz + 2; _ntl_gsetlength(x, sx); x1 = *x; _ntl_limb_t * NTL_RESTRICT xx = DATA(x1); const long Bnd = 1L << (NTL_BITS_PER_LONG-NTL_SP_NBITS); if (n <= Bnd) { _ntl_limb_t carry=0; for (i = 0; i < sz; i++) { const _ntl_limb_t *row = v[i]; ll_type acc; ll_mul(acc, row[0], b[0]); #if (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 4) switch (n) { case 16: ll_mul_add(acc, row[16-1], b[16-1]); case 15: ll_mul_add(acc, row[15-1], b[15-1]); case 14: ll_mul_add(acc, row[14-1], b[14-1]); case 13: ll_mul_add(acc, row[13-1], b[13-1]); case 12: ll_mul_add(acc, row[12-1], b[12-1]); case 11: ll_mul_add(acc, row[11-1], b[11-1]); case 10: ll_mul_add(acc, row[10-1], b[10-1]); case 9: ll_mul_add(acc, row[9-1], b[9-1]); case 8: ll_mul_add(acc, row[8-1], b[8-1]); case 7: ll_mul_add(acc, row[7-1], b[7-1]); case 6: ll_mul_add(acc, row[6-1], b[6-1]); case 5: ll_mul_add(acc, row[5-1], b[5-1]); case 4: ll_mul_add(acc, row[4-1], b[4-1]); case 3: ll_mul_add(acc, row[3-1], b[3-1]); case 2: ll_mul_add(acc, row[2-1], b[2-1]); } #elif (CRT_ALTCODE_UNROLL) long j = n; for (; j > 16; j -= 16) { ll_mul_add(acc, row[j-1], b[j-1]); ll_mul_add(acc, row[j-2], b[j-2]); ll_mul_add(acc, row[j-3], b[j-3]); ll_mul_add(acc, row[j-4], b[j-4]); ll_mul_add(acc, row[j-5], b[j-5]); ll_mul_add(acc, row[j-6], b[j-6]); ll_mul_add(acc, row[j-7], b[j-7]); ll_mul_add(acc, row[j-8], b[j-8]); ll_mul_add(acc, row[j-9], b[j-9]); ll_mul_add(acc, row[j-10], b[j-10]); ll_mul_add(acc, row[j-11], b[j-11]); ll_mul_add(acc, row[j-12], b[j-12]); ll_mul_add(acc, row[j-13], b[j-13]); ll_mul_add(acc, row[j-14], b[j-14]); ll_mul_add(acc, row[j-15], b[j-15]); ll_mul_add(acc, row[j-16], b[j-16]); } switch (j) { case 16: ll_mul_add(acc, row[16-1], b[16-1]); case 15: ll_mul_add(acc, row[15-1], b[15-1]); case 14: ll_mul_add(acc, row[14-1], b[14-1]); case 13: ll_mul_add(acc, row[13-1], b[13-1]); case 12: ll_mul_add(acc, row[12-1], b[12-1]); case 11: ll_mul_add(acc, row[11-1], b[11-1]); case 10: ll_mul_add(acc, row[10-1], b[10-1]); case 9: ll_mul_add(acc, row[9-1], b[9-1]); case 8: ll_mul_add(acc, row[8-1], b[8-1]); case 7: ll_mul_add(acc, row[7-1], b[7-1]); case 6: ll_mul_add(acc, row[6-1], b[6-1]); case 5: ll_mul_add(acc, row[5-1], b[5-1]); case 4: ll_mul_add(acc, row[4-1], b[4-1]); case 3: ll_mul_add(acc, row[3-1], b[3-1]); case 2: ll_mul_add(acc, row[2-1], b[2-1]); } #else for (j = 1; j < n; j++) ll_mul_add(acc, row[j], b[j]); #endif ll_add(acc, carry); xx[i] = ll_get_lo(acc); carry = ll_get_hi(acc); } xx[sz] = carry; xx[sz+1] = 0; } else { ll_type carry; ll_init(carry, 0); for (i = 0; i < sz; i++) { const _ntl_limb_t *row = v[i]; ll_type acc21; _ntl_limb_t acc0; { ll_type sum; ll_mul(sum, row[0], b[0]); #if (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 4) ll_mul_add(sum, row[1], b[1]); ll_mul_add(sum, row[2], b[2]); ll_mul_add(sum, row[3], b[3]); ll_mul_add(sum, row[4], b[4]); ll_mul_add(sum, row[5], b[5]); ll_mul_add(sum, row[6], b[6]); ll_mul_add(sum, row[7], b[7]); ll_mul_add(sum, row[8], b[8]); ll_mul_add(sum, row[9], b[9]); ll_mul_add(sum, row[10], b[10]); ll_mul_add(sum, row[11], b[11]); ll_mul_add(sum, row[12], b[12]); ll_mul_add(sum, row[13], b[13]); ll_mul_add(sum, row[14], b[14]); ll_mul_add(sum, row[15], b[15]); #elif (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 2) ll_mul_add(sum, row[1], b[1]); ll_mul_add(sum, row[2], b[2]); ll_mul_add(sum, row[3], b[3]); #else for (j = 1; j < Bnd; j++) ll_mul_add(sum, row[j], b[j]); #endif ll_init(acc21, ll_get_hi(sum)); acc0 = ll_get_lo(sum); } const _ntl_limb_t *ap = row; const long *tp = b; #if (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 2) long m = n - 4; ap += 4; tp += 4; for (; m >= 8; m -= 8, ap += 8, tp += 8) { { ll_type sum; ll_mul(sum, ap[0], tp[0]); ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } { ll_type sum; ll_mul(sum, ap[4+0], tp[4+0]); ll_mul_add(sum, ap[4+1], tp[4+1]); ll_mul_add(sum, ap[4+2], tp[4+2]); ll_mul_add(sum, ap[4+3], tp[4+3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } } for (; m >= 4; m -= 4, ap += 4, tp += 4) { ll_type sum; ll_mul(sum, ap[0], tp[0]); ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } #else long m; for (m = n-Bnd, ap += Bnd, tp += Bnd; m >= Bnd; m -= Bnd, ap += Bnd, tp += Bnd) { ll_type sum; ll_mul(sum, ap[0], tp[0]); #if (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 4) ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_mul_add(sum, ap[4], tp[4]); ll_mul_add(sum, ap[5], tp[5]); ll_mul_add(sum, ap[6], tp[6]); ll_mul_add(sum, ap[7], tp[7]); ll_mul_add(sum, ap[8], tp[8]); ll_mul_add(sum, ap[9], tp[9]); ll_mul_add(sum, ap[10], tp[10]); ll_mul_add(sum, ap[11], tp[11]); ll_mul_add(sum, ap[12], tp[12]); ll_mul_add(sum, ap[13], tp[13]); ll_mul_add(sum, ap[14], tp[14]); ll_mul_add(sum, ap[15], tp[15]); #else for (long j = 1; j < Bnd; j++) ll_mul_add(sum, ap[j], tp[j]); #endif ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } #endif if (m > 0) { ll_type sum; ll_mul(sum, ap[0], tp[0]); #if (CRT_ALTCODE_UNROLL && NTL_BITS_PER_LONG-NTL_SP_NBITS == 4) switch (m) { case 15: ll_mul_add(sum, ap[15-1], tp[15-1]); case 14: ll_mul_add(sum, ap[14-1], tp[14-1]); case 13: ll_mul_add(sum, ap[13-1], tp[13-1]); case 12: ll_mul_add(sum, ap[12-1], tp[12-1]); case 11: ll_mul_add(sum, ap[11-1], tp[11-1]); case 10: ll_mul_add(sum, ap[10-1], tp[10-1]); case 9: ll_mul_add(sum, ap[9-1], tp[9-1]); case 8: ll_mul_add(sum, ap[8-1], tp[8-1]); case 7: ll_mul_add(sum, ap[7-1], tp[7-1]); case 6: ll_mul_add(sum, ap[6-1], tp[6-1]); case 5: ll_mul_add(sum, ap[5-1], tp[5-1]); case 4: ll_mul_add(sum, ap[4-1], tp[4-1]); case 3: ll_mul_add(sum, ap[3-1], tp[3-1]); case 2: ll_mul_add(sum, ap[2-1], tp[2-1]); } #else for (m--, ap++, tp++; m > 0; m--, ap++, tp++) ll_mul_add(sum, ap[0], tp[0]); #endif ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } ll_add(carry, acc0); xx[i] = ll_get_lo(carry); ll_add(acc21, ll_get_hi(carry)); carry = acc21; } xx[sz] = ll_get_lo(carry); xx[sz+1] = ll_get_hi(carry); } STRIP(sx, xx); SIZE(x1) = sx; } #endif static void gadd_mul_many(_ntl_gbigint *res, _ntl_gbigint *a, long *b, long n, long sz) { _ntl_limb_t *xx, *yy; long i, sx; long sy; _ntl_limb_t carry; sx = sz + 2; if (MustAlloc(*res, sx)) _ntl_gsetlength(res, sx); xx = DATA(*res); for (i = 0; i < sx; i++) xx[i] = 0; for (i = 0; i < n; i++) { if (!a[i]) continue; yy = DATA(a[i]); sy = SIZE(a[i]); if (!sy || !b[i]) continue; carry = NTL_MPN(addmul_1)(xx, yy, sy, b[i]); yy = xx + sy; *yy = CLIP(*yy + carry); if (*yy < carry) { /* unsigned comparison! */ do { yy++; *yy = CLIP(*yy + 1); } while (*yy == 0); } } STRIP(sx, xx); SIZE(*res) = sx; } void _ntl_crt_struct_fast::eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *generic_tmp_vec) { _ntl_tmp_vec_crt_fast *tmp_vec = static_cast<_ntl_tmp_vec_crt_fast*> (generic_tmp_vec); long *val_vec = tmp_vec->val_vec.get(); _ntl_gbigint_wrapped *temps = tmp_vec->temps.get(); _ntl_gbigint_wrapped *rem_vec = tmp_vec->rem_vec.get(); long vec_len = (1L << levels) - 1; long i; for (i = 0; i < n; i++) { val_vec[i] = MulMod(b[i], inv_vec[i], primes[i]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long j1 = index_vec[i]; long j2 = index_vec[i+1]; gadd_mul_many(&rem_vec[i], &coeff_vec[j1], &val_vec[j1], j2-j1, SIZE(prod_vec[i])); } for (i = (1L << (levels-1)) - 2; i >= 0; i--) { _ntl_gmul(prod_vec[2*i+1], rem_vec[2*i+2], &temps[0]); _ntl_gmul(rem_vec[2*i+1], prod_vec[2*i+2], &temps[1]); _ntl_gadd(temps[0], temps[1], &rem_vec[i]); } /* temps[0] = rem_vec[0] mod prod_vec[0] (least absolute residue) */ _ntl_gmod(rem_vec[0], prod_vec[0], &temps[0]); _ntl_gsub(temps[0], prod_vec[0], &temps[1]); _ntl_gnegate(&temps[1]); if (_ntl_gcompare(temps[0], temps[1]) > 0) { _ntl_gnegate(&temps[1]); _ntl_gcopy(temps[1], &temps[0]); } _ntl_gmod(temps[0], modulus, &temps[1]); _ntl_gcopy(temps[1], x); } bool _ntl_crt_struct_basic::special() { return false; } #if (defined(NTL_TBL_CRT)) bool _ntl_crt_struct_tbl::special() { return false; } #endif bool _ntl_crt_struct_fast::special() { return true; } // ************** rem code #ifdef NTL_HAVE_LL_TYPE // This is the same logic as in sp_arith.h, but assumes // NumBits(d) == NTL_SP_NBITS static inline unsigned long tbl_red_inv(long d) { return (unsigned long) ( ((_ntl_ulonglong(1) << (NTL_SP_NBITS+NTL_BITS_PER_LONG))-1UL) / _ntl_ulonglong(d) ); } // assumes hi < d static inline long tbl_red_21(unsigned long hi, unsigned long lo, long d, unsigned long dinv) { unsigned long H = (hi << (NTL_BITS_PER_LONG-NTL_SP_NBITS)) | (lo >> NTL_SP_NBITS); unsigned long Q = ll_mul_hi(H, dinv) + H; unsigned long rr = lo - Q*cast_unsigned(d); // rr in [0..4*d) long r = sp_CorrectExcess(rr, 2*d); // r in [0..2*d) r = sp_CorrectExcess(r, d); return r; } // assumes x2 < d static inline unsigned long tbl_red_31(unsigned long x2, unsigned long x1, unsigned long x0, long d, unsigned long dinv) { long carry = tbl_red_21(x2, x1, d, dinv); return tbl_red_21(carry, x0, d, dinv); } #endif class _ntl_tmp_vec_rem_impl : public _ntl_tmp_vec { public: UniqueArray<_ntl_gbigint_wrapped> rem_vec; }; class _ntl_rem_struct_basic : public _ntl_rem_struct { public: long n; UniqueArray primes; void eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *tmp_vec); _ntl_tmp_vec *fetch(); }; class _ntl_rem_struct_fast : public _ntl_rem_struct { public: long n; long levels; UniqueArray primes; UniqueArray index_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec; long modulus_size; void eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *tmp_vec); _ntl_tmp_vec *fetch(); }; class _ntl_rem_struct_medium : public _ntl_rem_struct { public: long n; long levels; UniqueArray primes; UniqueArray index_vec; UniqueArray len_vec; UniqueArray<_ntl_limb_t> inv_vec; UniqueArray corr_vec; UniqueArray corraux_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec; void eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *tmp_vec); _ntl_tmp_vec *fetch(); }; #ifdef NTL_TBL_REM #define NTL_GAP_BITS (2*NTL_BITS_PER_LONG-NTL_SP_NBITS-NTL_ZZ_NBITS) // NOTE: do not allow NTL_GAP_BITS to exceed 28. // This is largely academic, but it avoids some potential // integer overflow issues. #if (NTL_GAP_BITS > 28) #undef NTL_GAP_BITS #define NTL_GAP_BITS (28) #endif class _ntl_rem_struct_tbl : public _ntl_rem_struct { public: long n; UniqueArray primes; UniqueArray<_ntl_limb_t> inv_primes; Unique2DArray<_ntl_limb_t> tbl; void eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *tmp_vec); _ntl_tmp_vec *fetch(); }; #endif _ntl_rem_struct *_ntl_rem_struct_build(long n, _ntl_gbigint modulus, long (*p)(long)) { #ifdef NTL_TBL_REM // FIXME: I should incorporate the logic from _ntl_general_rem_one_struct_apply // to keep the table sizes smaller #ifdef NTL_GMP_LIP if (n <= 800) #else if (1) // NOTE: without GMP, this is always the fastest #endif { UniqueArray q; UniqueArray<_ntl_limb_t> inv_primes; Unique2DArray<_ntl_limb_t> tbl; long i, j; long qq, t, t1; long sz = SIZE(modulus); q.SetLength(n); for (i = 0; i < n; i++) q[i] = p(i); inv_primes.SetLength(n); for (i = 0; i < n; i++) inv_primes[i] = tbl_red_inv(q[i]); tbl.SetDims(n, sz); for (i = 0; i < n; i++) { qq = q[i]; t = 1; for (j = 0; j < NTL_ZZ_NBITS; j++) { t += t; if (t >= qq) t -= qq; } t1 = 1; tbl[i][0] = 1; for (j = 1; j < sz; j++) { t1 = MulMod(t1, t, qq); tbl[i][j] = t1; } } UniquePtr<_ntl_rem_struct_tbl> R; R.make(); R->n = n; R->primes.move(q); R->inv_primes.move(inv_primes); R->tbl.move(tbl); return R.release(); } #endif #ifdef NTL_GMP_LIP if (0) // NOTE: this does not seem useful with GMP #else if (n > 600) // NOTE: this seems to be useful without GMP, but only if TBL_REM // does not work #endif { UniqueArray q; long i, j; long levels, vec_len; UniqueArray index_vec; UniqueArray len_vec, corr_vec; UniqueArray corraux_vec; UniqueArray<_ntl_limb_t> inv_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec; q.SetLength(n); for (i = 0; i < n; i++) q[i] = p(i); levels = 0; while ((n >> levels) >= 4) levels++; vec_len = (1L << levels) - 1; index_vec.SetLength(vec_len+1); len_vec.SetLength(vec_len); inv_vec.SetLength(vec_len); corr_vec.SetLength(n); corraux_vec.SetLength(n); prod_vec.SetLength(vec_len); index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 2; i >= 3; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); for (i = 3; i < vec_len; i++) len_vec[i] = _ntl_gsize(prod_vec[i]); /* Set len_vec[1] = len_vec[2] = * max(_ntl_gsize(modulus), len_vec[3..6]). * This is a bit paranoid, but it makes the code * more robust. */ j = _ntl_gsize(modulus); for (i = 3; i <= 6; i++) if (len_vec[i] > j) j = len_vec[i]; len_vec[1] = len_vec[2] = j; for (i = 3; i < vec_len; i++) inv_vec[i] = neg_inv_mod_limb(DATA(prod_vec[i])[0]); for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { for (j = index_vec[i]; j < index_vec[i+1]; j++) { corr_vec[j] = SpecialPower(len_vec[1] - len_vec[i], q[j]); corraux_vec[j] = PrepMulModPrecon(corr_vec[j], q[j]); } } UniquePtr<_ntl_rem_struct_medium> R; R.make(); R->n = n; R->levels = levels; R->primes.move(q); R->index_vec.move(index_vec); R->len_vec.move(len_vec); R->inv_vec.move(inv_vec); R->corr_vec.move(corr_vec); R->corraux_vec.move(corraux_vec); R->prod_vec.move(prod_vec); return R.release(); } if (n > 800) { UniqueArray q; long i, j; long levels, vec_len; UniqueArray index_vec; UniqueArray<_ntl_gbigint_wrapped> prod_vec; q.SetLength(n); for (i = 0; i < n; i++) q[i] = p(i); levels = 0; while ((n >> levels) >= 4) levels++; vec_len = (1L << levels) - 1; index_vec.SetLength(vec_len+1); prod_vec.SetLength(vec_len); index_vec[0] = 0; index_vec[1] = n; for (i = 0; i <= levels-2; i++) { long start = (1L << i) - 1; long finish = (1L << (i+1)) - 2; for (j = finish; j >= start; j--) { index_vec[2*j+2] = index_vec[j] + (index_vec[j+1] - index_vec[j])/2; index_vec[2*j+1] = index_vec[j]; } index_vec[2*finish+3] = n; } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { /* multiply primes index_vec[i]..index_vec[i+1]-1 into * prod_vec[i] */ _ntl_gone(&prod_vec[i]); for (j = index_vec[i]; j < index_vec[i+1]; j++) _ntl_gsmul(prod_vec[i], q[j], &prod_vec[i]); } for (i = (1L << (levels-1)) - 2; i >= 3; i--) _ntl_gmul(prod_vec[2*i+1], prod_vec[2*i+2], &prod_vec[i]); UniquePtr<_ntl_rem_struct_fast> R; R.make(); R->n = n; R->levels = levels; R->primes.move(q); R->index_vec.move(index_vec); R->prod_vec.move(prod_vec); R->modulus_size = _ntl_gsize(modulus); return R.release(); } { // basic case UniqueArray q; long i; UniquePtr<_ntl_rem_struct_basic> R; R.make(); R->n = n; R->primes.SetLength(n); for (i = 0; i < n; i++) R->primes[i] = p(i); return R.release(); } } _ntl_tmp_vec *_ntl_rem_struct_basic::fetch() { return 0; } #ifdef NTL_TBL_REM _ntl_tmp_vec *_ntl_rem_struct_tbl::fetch() { return 0; } #endif _ntl_tmp_vec *_ntl_rem_struct_fast::fetch() { long vec_len = (1L << levels) - 1; UniquePtr<_ntl_tmp_vec_rem_impl> res; res.make(); res->rem_vec.SetLength(vec_len); _ntl_gbigint_wrapped *rem_vec = res->rem_vec.get(); long i; /* allocate length in advance to streamline eval code */ _ntl_gsetlength(&rem_vec[1], modulus_size); _ntl_gsetlength(&rem_vec[2], modulus_size); for (i = 1; i < (1L << (levels-1)) - 1; i++) { _ntl_gsetlength(&rem_vec[2*i+1], _ntl_gsize(prod_vec[2*i+1])); _ntl_gsetlength(&rem_vec[2*i+2], _ntl_gsize(prod_vec[2*i+2])); } return res.release(); } _ntl_tmp_vec *_ntl_rem_struct_medium::fetch() { long vec_len = (1L << levels) - 1; UniquePtr<_ntl_tmp_vec_rem_impl> res; res.make(); res->rem_vec.SetLength(vec_len); _ntl_gbigint_wrapped *rem_vec = res->rem_vec.get(); long i; /* allocate length in advance to streamline eval code */ _ntl_gsetlength(&rem_vec[0], len_vec[1]); /* a special temp */ for (i = 1; i < vec_len; i++) _ntl_gsetlength(&rem_vec[i], len_vec[i]); return res.release(); } #ifdef NTL_TBL_REM #if (NTL_GAP_BITS == 2) // special case, some loop unrolling: slightly faster void _ntl_rem_struct_tbl::eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *generic_tmp_vec) { if (ZEROP(a)) { long i; for (i = 0; i < n; i++) x[i] = 0; return; } long sa = SIZE(a); _ntl_limb_t *adata = DATA(a); if (sa <= 4) { long i; for (i = 0; i < n; i++) { _ntl_limb_t *tp = tbl[i]; ll_type acc; ll_init(acc, adata[0]); long j; for (j = 1; j < sa; j++) ll_mul_add(acc, adata[j], tp[j]); _ntl_limb_t accvec[2]; x[i] = tbl_red_31(0, ll_get_hi(acc), ll_get_lo(acc), primes[i], inv_primes[i]); } } else { long i; for (i = 0; i < n; i++) { _ntl_limb_t *ap = adata; _ntl_limb_t *tp = tbl[i]; ll_type acc21; _ntl_limb_t acc0; { ll_type sum; ll_init(sum, ap[0]); ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_init(acc21, ll_get_hi(sum)); acc0 = ll_get_lo(sum); } long m=sa-4; ap += 4; tp += 4; for (; m >= 8; m -= 8, ap += 8, tp += 8) { { ll_type sum; ll_mul(sum, ap[0], tp[0]); ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } { ll_type sum; ll_mul(sum, ap[4+0], tp[4+0]); ll_mul_add(sum, ap[4+1], tp[4+1]); ll_mul_add(sum, ap[4+2], tp[4+2]); ll_mul_add(sum, ap[4+3], tp[4+3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } } for (; m >= 4; m -= 4, ap += 4, tp += 4) { ll_type sum; ll_mul(sum, ap[0], tp[0]); ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (m > 0) { ll_type sum; ll_mul(sum, ap[0], tp[0]); for (m--, ap++, tp++; m > 0; m--, ap++, tp++) ll_mul_add(sum, ap[0], tp[0]); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } x[i] = tbl_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, primes[i], inv_primes[i]); } } } #else // General case: some loop unrolling (also using "Duff's Device") // for the case where BPL-SPNBITS == 4: this is the common // case on 64-bit machines. The loop unrolling and Duff seems // to shave off 5-10% #define TBL_UNROLL (1) void _ntl_rem_struct_tbl::eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *generic_tmp_vec) { if (ZEROP(a)) { long i; for (i = 0; i < n; i++) x[i] = 0; return; } long sa = SIZE(a); _ntl_limb_t *adata = DATA(a); const long Bnd = 1L << NTL_GAP_BITS; if (sa <= Bnd) { long i; for (i = 0; i < n; i++) { _ntl_limb_t *tp = tbl[i]; ll_type acc; ll_init(acc, adata[0]); #if (TBL_UNROLL && NTL_GAP_BITS == 4) switch (sa) { case 16: ll_mul_add(acc, adata[16-1], tp[16-1]); case 15: ll_mul_add(acc, adata[15-1], tp[15-1]); case 14: ll_mul_add(acc, adata[14-1], tp[14-1]); case 13: ll_mul_add(acc, adata[13-1], tp[13-1]); case 12: ll_mul_add(acc, adata[12-1], tp[12-1]); case 11: ll_mul_add(acc, adata[11-1], tp[11-1]); case 10: ll_mul_add(acc, adata[10-1], tp[10-1]); case 9: ll_mul_add(acc, adata[9-1], tp[9-1]); case 8: ll_mul_add(acc, adata[8-1], tp[8-1]); case 7: ll_mul_add(acc, adata[7-1], tp[7-1]); case 6: ll_mul_add(acc, adata[6-1], tp[6-1]); case 5: ll_mul_add(acc, adata[5-1], tp[5-1]); case 4: ll_mul_add(acc, adata[4-1], tp[4-1]); case 3: ll_mul_add(acc, adata[3-1], tp[3-1]); case 2: ll_mul_add(acc, adata[2-1], tp[2-1]); } #elif (TBL_UNROLL) long j = sa; for (; j > 16; j -= 16) { ll_mul_add(acc, adata[j-1], tp[j-1]); ll_mul_add(acc, adata[j-2], tp[j-2]); ll_mul_add(acc, adata[j-3], tp[j-3]); ll_mul_add(acc, adata[j-4], tp[j-4]); ll_mul_add(acc, adata[j-5], tp[j-5]); ll_mul_add(acc, adata[j-6], tp[j-6]); ll_mul_add(acc, adata[j-7], tp[j-7]); ll_mul_add(acc, adata[j-8], tp[j-8]); ll_mul_add(acc, adata[j-9], tp[j-9]); ll_mul_add(acc, adata[j-10], tp[j-10]); ll_mul_add(acc, adata[j-11], tp[j-11]); ll_mul_add(acc, adata[j-12], tp[j-12]); ll_mul_add(acc, adata[j-13], tp[j-13]); ll_mul_add(acc, adata[j-14], tp[j-14]); ll_mul_add(acc, adata[j-15], tp[j-15]); ll_mul_add(acc, adata[j-16], tp[j-16]); } switch (j) { case 16: ll_mul_add(acc, adata[16-1], tp[16-1]); case 15: ll_mul_add(acc, adata[15-1], tp[15-1]); case 14: ll_mul_add(acc, adata[14-1], tp[14-1]); case 13: ll_mul_add(acc, adata[13-1], tp[13-1]); case 12: ll_mul_add(acc, adata[12-1], tp[12-1]); case 11: ll_mul_add(acc, adata[11-1], tp[11-1]); case 10: ll_mul_add(acc, adata[10-1], tp[10-1]); case 9: ll_mul_add(acc, adata[9-1], tp[9-1]); case 8: ll_mul_add(acc, adata[8-1], tp[8-1]); case 7: ll_mul_add(acc, adata[7-1], tp[7-1]); case 6: ll_mul_add(acc, adata[6-1], tp[6-1]); case 5: ll_mul_add(acc, adata[5-1], tp[5-1]); case 4: ll_mul_add(acc, adata[4-1], tp[4-1]); case 3: ll_mul_add(acc, adata[3-1], tp[3-1]); case 2: ll_mul_add(acc, adata[2-1], tp[2-1]); } #else long j; for (j = 1; j < sa; j++) ll_mul_add(acc, adata[j], tp[j]); #endif x[i] = tbl_red_31(0, ll_get_hi(acc), ll_get_lo(acc), primes[i], inv_primes[i]); } } else { long i; for (i = 0; i < n; i++) { _ntl_limb_t *ap = adata; _ntl_limb_t *tp = tbl[i]; ll_type acc21; _ntl_limb_t acc0; { ll_type sum; ll_init(sum, ap[0]); #if (TBL_UNROLL && NTL_GAP_BITS == 4) ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_mul_add(sum, ap[4], tp[4]); ll_mul_add(sum, ap[5], tp[5]); ll_mul_add(sum, ap[6], tp[6]); ll_mul_add(sum, ap[7], tp[7]); ll_mul_add(sum, ap[8], tp[8]); ll_mul_add(sum, ap[9], tp[9]); ll_mul_add(sum, ap[10], tp[10]); ll_mul_add(sum, ap[11], tp[11]); ll_mul_add(sum, ap[12], tp[12]); ll_mul_add(sum, ap[13], tp[13]); ll_mul_add(sum, ap[14], tp[14]); ll_mul_add(sum, ap[15], tp[15]); #else for (long j = 1; j < Bnd; j++) ll_mul_add(sum, ap[j], tp[j]); #endif ll_init(acc21, ll_get_hi(sum)); acc0 = ll_get_lo(sum); } long m; for (m = sa-Bnd, ap += Bnd, tp += Bnd; m >= Bnd; m -= Bnd, ap += Bnd, tp += Bnd) { ll_type sum; ll_mul(sum, ap[0], tp[0]); #if (TBL_UNROLL && NTL_GAP_BITS == 4) ll_mul_add(sum, ap[1], tp[1]); ll_mul_add(sum, ap[2], tp[2]); ll_mul_add(sum, ap[3], tp[3]); ll_mul_add(sum, ap[4], tp[4]); ll_mul_add(sum, ap[5], tp[5]); ll_mul_add(sum, ap[6], tp[6]); ll_mul_add(sum, ap[7], tp[7]); ll_mul_add(sum, ap[8], tp[8]); ll_mul_add(sum, ap[9], tp[9]); ll_mul_add(sum, ap[10], tp[10]); ll_mul_add(sum, ap[11], tp[11]); ll_mul_add(sum, ap[12], tp[12]); ll_mul_add(sum, ap[13], tp[13]); ll_mul_add(sum, ap[14], tp[14]); ll_mul_add(sum, ap[15], tp[15]); #else for (long j = 1; j < Bnd; j++) ll_mul_add(sum, ap[j], tp[j]); #endif ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (m > 0) { ll_type sum; ll_mul(sum, ap[0], tp[0]); #if (TBL_UNROLL && NTL_GAP_BITS == 4) switch (m) { case 15: ll_mul_add(sum, ap[15-1], tp[15-1]); case 14: ll_mul_add(sum, ap[14-1], tp[14-1]); case 13: ll_mul_add(sum, ap[13-1], tp[13-1]); case 12: ll_mul_add(sum, ap[12-1], tp[12-1]); case 11: ll_mul_add(sum, ap[11-1], tp[11-1]); case 10: ll_mul_add(sum, ap[10-1], tp[10-1]); case 9: ll_mul_add(sum, ap[9-1], tp[9-1]); case 8: ll_mul_add(sum, ap[8-1], tp[8-1]); case 7: ll_mul_add(sum, ap[7-1], tp[7-1]); case 6: ll_mul_add(sum, ap[6-1], tp[6-1]); case 5: ll_mul_add(sum, ap[5-1], tp[5-1]); case 4: ll_mul_add(sum, ap[4-1], tp[4-1]); case 3: ll_mul_add(sum, ap[3-1], tp[3-1]); case 2: ll_mul_add(sum, ap[2-1], tp[2-1]); } #else for (m--, ap++, tp++; m > 0; m--, ap++, tp++) ll_mul_add(sum, ap[0], tp[0]); #endif ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } x[i] = tbl_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, primes[i], inv_primes[i]); } } } #endif #endif void _ntl_rem_struct_basic::eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *generic_tmp_vec) { long *q = primes.get(); long j; _ntl_limb_t *adata; long sa; if (!a) sa = 0; else sa = SIZE(a); if (sa == 0) { for (j = 0; j < n; j++) x[j] = 0; return; } adata = DATA(a); for (j = 0; j < n; j++) x[j] = NTL_MPN(mod_1)(adata, sa, q[j]); } void _ntl_rem_struct_fast::eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *generic_tmp_vec) { long *q = primes.get(); _ntl_gbigint_wrapped *rem_vec = (static_cast<_ntl_tmp_vec_rem_impl *> (generic_tmp_vec))->rem_vec.get(); long vec_len = (1L << levels) - 1; long i, j; if (ZEROP(a)) { for (j = 0; j < n; j++) x[j] = 0; return; } _ntl_gcopy(a, &rem_vec[1]); _ntl_gcopy(a, &rem_vec[2]); for (i = 1; i < (1L << (levels-1)) - 1; i++) { gmod_simple(rem_vec[i], prod_vec[2*i+1], &rem_vec[2*i+1]); gmod_simple(rem_vec[i], prod_vec[2*i+2], &rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long lo = index_vec[i]; long hi = index_vec[i+1]; _ntl_limb_t *s1p = DATA(rem_vec[i]); long s1size = SIZE(rem_vec[i]); if (s1size == 0) { for (j = lo; j (generic_tmp_vec))->rem_vec.get(); long vec_len = (1L << levels) - 1; long i, j; if (ZEROP(a)) { for (j = 0; j < n; j++) x[j] = 0; return; } _ntl_gcopy(a, &rem_vec[1]); _ntl_gcopy(a, &rem_vec[2]); for (i = 1; i < (1L << (levels-1)) - 1; i++) { _ntl_gcopy(rem_vec[i], &rem_vec[0]); redc(rem_vec[0], prod_vec[2*i+1], len_vec[i]-len_vec[2*i+1], inv_vec[2*i+1], rem_vec[2*i+1]); redc(rem_vec[i], prod_vec[2*i+2], len_vec[i]-len_vec[2*i+2], inv_vec[2*i+2], rem_vec[2*i+2]); } for (i = (1L << (levels-1)) - 1; i < vec_len; i++) { long lo = index_vec[i]; long hi = index_vec[i+1]; _ntl_limb_t *s1p = DATA(rem_vec[i]); long s1size = SIZE(rem_vec[i]); if (s1size == 0) { for (j = lo; j < hi; j++) x[j] = 0; } else { for (j = lo; j < hi; j++) { long t = NTL_MPN(mod_1)(s1p, s1size, q[j]); x[j] = MulModPrecon(t, corr_vec[j], q[j], corraux_vec[j]); } } } } /* routines for x += a*b for multi-precision b */ void _ntl_gaorsmul(_ntl_gbigint x, _ntl_gbigint y, long sub, _ntl_gbigint *ww) { GRegister(tmp); _ntl_gmul(x, y, &tmp); if (sub) _ntl_gsub(*ww, tmp, ww); else _ntl_gadd(*ww, tmp, ww); } void _ntl_gaddmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww) { _ntl_gaorsmul(x, y, 0, ww); } void _ntl_gsubmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww) { _ntl_gaorsmul(x, y, 1, ww); } /* routines for x += a*b for single-precision b * Lightly massaged code taken from GMP's mpz routines */ static inline void _ntl_mpn_com_n(_ntl_limb_t *d, _ntl_limb_t *s, long n) { do { *d++ = CLIP(~ *s++); } while (--n); } #if 0 #define _ntl_mpn_com_n(d,s,n) \ do { \ _ntl_limb_t * __d = (d); \ _ntl_limb_t * __s = (s); \ long __n = (n); \ do \ *__d++ = CLIP(~ *__s++); \ while (--__n); \ } while (0) #endif static inline void _ntl_MPN_MUL_1C(_ntl_limb_t& cout, _ntl_limb_t *dst, _ntl_limb_t *src, long size, _ntl_limb_t n, _ntl_limb_t cin) { _ntl_limb_t cy; cy = NTL_MPN(mul_1) (dst, src, size, n); cout = CLIP(cy + NTL_MPN(add_1) (dst, dst, size, cin)); } #if 0 #define _ntl_MPN_MUL_1C(cout, dst, src, size, n, cin) \ do { \ _ntl_limb_t __cy; \ __cy = NTL_MPN(mul_1) (dst, src, size, n); \ (cout) = CLIP(__cy + NTL_MPN(add_1) (dst, dst, size, cin)); \ } while (0) #endif static inline void _ntl_g_inc(_ntl_limb_t *p, long n) { while (n > 0) { *p = CLIP(*p + 1); if (*p != 0) break; p++; n--; } } #if 0 #define _ntl_g_inc(p, n) \ do { \ _ntl_limb_t * __p = (p); \ long __n = (n); \ while (__n > 0) { \ *__p = CLIP(*__p + 1); \ if (*__p != 0) break; \ __p++; \ __n--; \ } \ } while (0); #endif static inline void _ntl_g_inc_carry(_ntl_limb_t& c, _ntl_limb_t *p, long n) { long addc = 1; while (n > 0) { *p = CLIP(*p + 1); if (*p != 0) { addc = 0; break; } p++; n--; } c = CLIP(c + addc); } #if 0 #define _ntl_g_inc_carry(c, p, n) \ do { \ _ntl_limb_t * __p = (p); \ long __n = (n); \ long __addc = 1; \ while (__n > 0) { \ *__p = CLIP(*__p + 1); \ if (*__p != 0) { __addc = 0; break; } \ __p++; \ __n--; \ } \ c = CLIP(c + __addc); \ } while (0); #endif static inline void _ntl_g_dec(_ntl_limb_t *p, long n) { _ntl_limb_t tmp; while (n > 0) { tmp = *p; *p = CLIP(*p - 1); if (tmp != 0) break; p++; n--; } } #if 0 #define _ntl_g_dec(p, n) \ do { \ _ntl_limb_t * __p = (p); \ _ntl_limb_t __tmp; \ long __n = (n); \ while (__n > 0) { \ __tmp = *__p; \ *__p = CLIP(*__p - 1); \ if (__tmp != 0) break; \ __p++; \ __n--; \ } \ } while (0); #endif /* sub==0 means an addmul w += x*y, sub==1 means a submul w -= x*y. */ void _ntl_gaorsmul_1(_ntl_gbigint x, long yy, long sub, _ntl_gbigint *ww) { long xsize, xneg, wsize, wneg, new_wsize, min_size, dsize; _ntl_gbigint w; _ntl_limb_t *xp; _ntl_limb_t *wp; _ntl_limb_t cy; _ntl_limb_t y; if (ZEROP(x) || yy == 0) return; if (ZEROP(*ww)) { _ntl_gsmul(x, yy, ww); if (sub) SIZE(*ww) = -SIZE(*ww); return; } if (yy == 1) { if (sub) _ntl_gsub(*ww, x, ww); else _ntl_gadd(*ww, x, ww); return; } if (yy == -1) { if (sub) _ntl_gadd(*ww, x, ww); else _ntl_gsub(*ww, x, ww); return; } if (*ww == x) { GRegister(tmp); _ntl_gsmul(x, yy, &tmp); if (sub) _ntl_gsub(*ww, tmp, ww); else _ntl_gadd(*ww, tmp, ww); return; } y = ABS(yy); if (XCLIP(y)) { GRegister(xyy); _ntl_gintoz(yy, &xyy); _ntl_gaorsmul(x, xyy, sub, ww); return; } GET_SIZE_NEG(xsize, xneg, x); sub = XOR(sub, xneg); sub = XOR(sub, yy < 0); w = *ww; GET_SIZE_NEG(wsize, wneg, w); sub = XOR(sub, wneg); new_wsize = max(wsize, xsize); min_size = min(wsize, xsize); if (MustAlloc(w, new_wsize+1)) { _ntl_gsetlength(&w, new_wsize+1); *ww = w; } wp = DATA(w); xp = DATA(x); if (sub == 0) { /* addmul of absolute values */ cy = NTL_MPN(addmul_1) (wp, xp, min_size, y); wp += min_size; xp += min_size; dsize = xsize - wsize; if (dsize != 0) { _ntl_limb_t cy2; if (dsize > 0) { cy2 = NTL_MPN(mul_1) (wp, xp, dsize, y); } else { dsize = -dsize; cy2 = 0; } cy = CLIP(cy2 + NTL_MPN(add_1) (wp, wp, dsize, cy)); } wp[dsize] = cy; new_wsize += (cy != 0); } else { /* submul of absolute values */ cy = NTL_MPN(submul_1) (wp, xp, min_size, y); if (wsize >= xsize) { /* if w bigger than x, then propagate borrow through it */ if (wsize != xsize) { cy = NTL_MPN(sub_1) (wp+xsize, wp+xsize, wsize-xsize, cy); } if (cy != 0) { /* Borrow out of w, take twos complement negative to get absolute value, flip sign of w. */ wp[new_wsize] = CLIP(~-cy); /* extra limb is 0-cy */ _ntl_mpn_com_n (wp, wp, new_wsize); new_wsize++; _ntl_g_inc(wp, new_wsize); wneg = XOR(wneg, 1); } } else /* wsize < xsize */ { /* x bigger than w, so want x*y-w. Submul has given w-x*y, so take twos complement and use an mpn_mul_1 for the rest. */ _ntl_limb_t cy2; /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */ _ntl_mpn_com_n (wp, wp, wsize); _ntl_g_inc_carry(cy, wp, wsize); cy = CLIP(cy-1); /* If cy-1 == -1 then hold that -1 for latter. mpn_submul_1 never returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */ cy2 = (cy == CLIP(_ntl_limb_t(-1))); cy = CLIP(cy + cy2); _ntl_MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy); wp[new_wsize] = cy; new_wsize += (cy != 0); /* Apply any -1 from above. The value at wp+wsize is non-zero because y!=0 and the high limb of x will be non-zero. */ if (cy2) { _ntl_g_dec(wp+wsize, new_wsize-wsize); } wneg = XOR(wneg, 1); } /* submul can produce high zero limbs due to cancellation, both when w has more limbs or x has more */ STRIP(new_wsize, wp); } if (wneg) new_wsize = -new_wsize; SIZE(w) = new_wsize; } void _ntl_gsaddmul(_ntl_gbigint x, long yy, _ntl_gbigint *ww) { _ntl_gaorsmul_1(x, yy, 0, ww); } void _ntl_gssubmul(_ntl_gbigint x, long yy, _ntl_gbigint *ww) { _ntl_gaorsmul_1(x, yy, 1, ww); } // general preconditioned remainder #ifndef NTL_VIABLE_LL struct _ntl_general_rem_one_struct { }; _ntl_general_rem_one_struct * _ntl_general_rem_one_struct_build(long p) { return 0; } long _ntl_general_rem_one_struct_apply(_ntl_gbigint a, long p, _ntl_general_rem_one_struct *pinfo) { return _ntl_gsmod(a, p); } void _ntl_general_rem_one_struct_delete(_ntl_general_rem_one_struct *pinfo) { } #else #define REM_ONE_SZ (128) struct _ntl_general_rem_one_struct { sp_ll_reduce_struct red_struct; long Bnd; UniqueArray<_ntl_limb_t> tbl; }; _ntl_general_rem_one_struct * _ntl_general_rem_one_struct_build(long p) { if (p < 2 || p >= NTL_SP_BOUND) LogicError("_ntl_general_rem_one_struct_build: bad args (p)"); UniquePtr<_ntl_general_rem_one_struct> pinfo; pinfo.make(); pinfo->red_struct = make_sp_ll_reduce_struct(p); long pbits = _ntl_g2logs(p); long gapbits = min(28, 2*NTL_BITS_PER_LONG - pbits - NTL_ZZ_NBITS); // hold gapbits to a max of 28 to avoid some potential overflow // issues pinfo->Bnd = 1L << gapbits; pinfo->tbl.SetLength(REM_ONE_SZ+3); long t = 1; for (long j = 0; j < NTL_ZZ_NBITS; j++) { t += t; if (t >= p) t -= p; } long t2 = t; for (long j = NTL_ZZ_NBITS; j < NTL_BITS_PER_LONG; j++) { t2 += t2; if (t2 >= p) t2 -= p; } long t1 = 1; pinfo->tbl[0] = 1; for (long j = 1; j <= REM_ONE_SZ; j++) { t1 = MulMod(t1, t, p); pinfo->tbl[j] = t1; } // careful! for non-empty nails, we have to initialize // the last two table entries differently for (long j = REM_ONE_SZ+1; j < REM_ONE_SZ+3; j++) { t1 = MulMod(t1, t2, p); pinfo->tbl[j] = t1; } return pinfo.release(); } long _ntl_general_rem_one_struct_apply1(_ntl_limb_t *a_data, long a_sz, long a_neg, long p, _ntl_general_rem_one_struct *pinfo) { sp_ll_reduce_struct red_struct = pinfo->red_struct; long Bnd = pinfo->Bnd; _ntl_limb_t *tbl = pinfo->tbl.elts(); long idx = ((cast_unsigned(a_sz+REM_ONE_SZ-1)/REM_ONE_SZ)-1)*REM_ONE_SZ; ll_type leftover; long sz = a_sz-idx; a_data += idx; for ( ; ; sz = REM_ONE_SZ, a_data -= REM_ONE_SZ, idx -= REM_ONE_SZ) { if (sz <= Bnd) { ll_type acc; ll_init(acc, 0); { long j = 0; for (; j <= sz-16; j += 16) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); } for (; j <= sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); } if (idx + REM_ONE_SZ >= a_sz) { // first time if (idx == 0) { // last time long res = sp_ll_red_31(0, ll_get_hi(acc), ll_get_lo(acc), p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else { ll_mul(leftover, ll_get_lo(acc), tbl[REM_ONE_SZ]); ll_mul_add(leftover, ll_get_hi(acc), tbl[REM_ONE_SZ+1]); } } else { ll_type acc21; _ntl_limb_t acc0; ll_add(leftover, ll_get_lo(acc)); acc0 = ll_get_lo(leftover); ll_init(acc21, ll_get_hi(leftover)); ll_add(acc21, ll_get_hi(acc)); if (idx == 0) { // last time long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else { ll_mul(leftover, acc0, tbl[REM_ONE_SZ]); ll_mul_add(leftover, ll_get_lo(acc21), tbl[REM_ONE_SZ+1]); ll_mul_add(leftover, ll_get_hi(acc21), tbl[REM_ONE_SZ+2]); } } } else { ll_type acc21; ll_init(acc21, 0); _ntl_limb_t acc0 = 0; if (Bnd > 16) { long jj = 0; for (; jj <= sz-Bnd; jj += Bnd) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= jj+Bnd-16; j += 16) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); } acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } } else if (Bnd == 16) { long jj = 0; for (; jj <= sz-16; jj += 16) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } } else if (Bnd == 8) { long jj = 0; for (; jj <= sz-8; jj += 8) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j < sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } } else /* Bnd == 4 */ { long jj = 0; for (; jj <= sz-4; jj += 4) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j < sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } } if (idx + REM_ONE_SZ < a_sz) { // not first time ll_add(leftover, acc0); acc0 = ll_get_lo(leftover); ll_add(acc21, ll_get_hi(leftover)); } if (idx == 0) { // last time long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else { ll_mul(leftover, acc0, tbl[REM_ONE_SZ]); ll_mul_add(leftover, ll_get_lo(acc21), tbl[REM_ONE_SZ+1]); ll_mul_add(leftover, ll_get_hi(acc21), tbl[REM_ONE_SZ+2]); } } } } long _ntl_general_rem_one_struct_apply(_ntl_gbigint a, long p, _ntl_general_rem_one_struct *pinfo) { if (ZEROP(a)) return 0; if (!pinfo) { return _ntl_gsmod(a, p); } sp_ll_reduce_struct red_struct = pinfo->red_struct; long Bnd = pinfo->Bnd; _ntl_limb_t *tbl = pinfo->tbl.elts(); long a_sz, a_neg; _ntl_limb_t *a_data; GET_SIZE_NEG(a_sz, a_neg, a); a_data = DATA(a); if (a_sz > REM_ONE_SZ) { return _ntl_general_rem_one_struct_apply1(a_data, a_sz, a_neg, p, pinfo); } if (a_sz <= Bnd) { ll_type acc; ll_init(acc, 0); { long j = 0; for (; j <= a_sz-16; j += 16) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); } for (; j <= a_sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < a_sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); } long res = sp_ll_red_31(0, ll_get_hi(acc), ll_get_lo(acc), p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else if (Bnd > 16) { ll_type acc21; ll_init(acc21, 0); _ntl_limb_t acc0 = 0; long jj = 0; for (; jj <= a_sz-Bnd; jj += Bnd) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= jj+Bnd-16; j += 16) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); } acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < a_sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= a_sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < a_sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else if (Bnd == 16) { ll_type acc21; ll_init(acc21, 0); _ntl_limb_t acc0 = 0; long jj = 0; for (; jj <= a_sz-16; jj += 16) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_mul_add(acc, a_data[j+8], tbl[j+8]); ll_mul_add(acc, a_data[j+9], tbl[j+9]); ll_mul_add(acc, a_data[j+10], tbl[j+10]); ll_mul_add(acc, a_data[j+11], tbl[j+11]); ll_mul_add(acc, a_data[j+12], tbl[j+12]); ll_mul_add(acc, a_data[j+13], tbl[j+13]); ll_mul_add(acc, a_data[j+14], tbl[j+14]); ll_mul_add(acc, a_data[j+15], tbl[j+15]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < a_sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j <= a_sz-4; j += 4) { ll_mul_add(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); } for (; j < a_sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } #if (NTL_NAIL_BITS == 0 && NTL_BITS_PER_LONG-NTL_SP_NBITS==4) // DIRT: only works if no nails // NOTE: this is a very minor optimization long res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); #else long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); #endif if (a_neg) res = NegateMod(res, p); return res; } else if (Bnd == 8) { ll_type acc21; ll_init(acc21, 0); _ntl_limb_t acc0 = 0; long jj = 0; for (; jj <= a_sz-8; jj += 8) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_mul_add(acc, a_data[j+4], tbl[j+4]); ll_mul_add(acc, a_data[j+5], tbl[j+5]); ll_mul_add(acc, a_data[j+6], tbl[j+6]); ll_mul_add(acc, a_data[j+7], tbl[j+7]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < a_sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j < a_sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); if (a_neg) res = NegateMod(res, p); return res; } else /* Bnd == 4 */ { ll_type acc21; ll_init(acc21, 0); _ntl_limb_t acc0 = 0; long jj = 0; for (; jj <= a_sz-4; jj += 4) { ll_type acc; long j = jj; ll_mul(acc, a_data[j+0], tbl[j+0]); ll_mul_add(acc, a_data[j+1], tbl[j+1]); ll_mul_add(acc, a_data[j+2], tbl[j+2]); ll_mul_add(acc, a_data[j+3], tbl[j+3]); ll_add(acc, acc0); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } if (jj < a_sz) { ll_type acc; ll_init(acc, acc0); long j = jj; for (; j < a_sz; j++) ll_mul_add(acc, a_data[j+0], tbl[j+0]); acc0 = ll_get_lo(acc); ll_add(acc21, ll_get_hi(acc)); } #if (NTL_NAIL_BITS == 0 && NTL_BITS_PER_LONG-NTL_SP_NBITS==2) // DIRT: only works if no nails // NOTE: this is a very minor optimization long res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); #else long res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, red_struct); #endif if (a_neg) res = NegateMod(res, p); return res; } } void _ntl_general_rem_one_struct_delete(_ntl_general_rem_one_struct *pinfo) { delete pinfo; } #endif void _ntl_quick_accum_begin(_ntl_gbigint *xp, long sz) { long sbuf = sz+2; _ntl_gbigint x = *xp; if (MustAlloc(x, sbuf)) { _ntl_gsetlength(&x, sbuf); *xp = x; } _ntl_limb_t *xx = DATA(x); for (long i = 0; i < sbuf; i++) xx[i] = 0; SIZE(x) = sbuf; } void _ntl_quick_accum_muladd(_ntl_gbigint x, _ntl_gbigint y, long b) { if (!y) return; _ntl_limb_t *yy = DATA(y); long sy = SIZE(y); if (!sy || !b) return; _ntl_limb_t *xx = DATA(x); _ntl_limb_t carry = NTL_MPN(addmul_1)(xx, yy, sy, b); yy = xx + sy; *yy = CLIP(*yy + carry); if (*yy < carry) { /* unsigned comparison! */ do { yy++; *yy = CLIP(*yy + 1); } while (*yy == 0); } } void _ntl_quick_accum_end(_ntl_gbigint x) { _ntl_limb_t *xx = DATA(x); long sx = SIZE(x); STRIP(sx, xx); SIZE(x) = sx; } #ifdef NTL_PROVIDES_SS_LIP_IMPL void _ntl_leftrotate(_ntl_gbigint *a, const _ntl_gbigint *b, long e, _ntl_gbigint p, long n, _ntl_gbigint *scratch) { if (e == 0 || ZEROP(*b)) { _ntl_gcopy(*b, a); return; } long sb, nwords; if (a == b || ((unsigned long) n) % NTL_ZZ_NBITS != 0 || (sb = SIZE(*b)) == 1 + (nwords = ((unsigned long) n) / NTL_ZZ_NBITS)) { _ntl_grshift(*b, n-e, scratch); _ntl_glowbits(*b, n-e, a); _ntl_glshift(*a, e, a); if (_ntl_gcompare(*a, *scratch) < 0) { _ntl_gswitchbit(a, n); _ntl_gsadd(*a, 1, a); _ntl_gsubpos(*a, *scratch, a); } else { _ntl_gsubpos(*a, *scratch, a); } return; } long ewords = ((unsigned long) e) / NTL_ZZ_NBITS; long ebits = ((unsigned long) e) % NTL_ZZ_NBITS; if (MustAlloc(*a, nwords+1)) _ntl_gsetlength(a, nwords+1); _ntl_limb_t *adata = DATA(*a); _ntl_limb_t *bdata = DATA(*b); long special_carry = 0; long sa = 0; if (ewords) { long hiwords = sb - (nwords-ewords); if (hiwords > 0) { _ntl_limb_t borrow = NTL_MPN(neg)(adata, bdata + (nwords-ewords), hiwords); if (hiwords < ewords) { if (borrow) { for (long i = hiwords; i < ewords; i++) adata[i] = _ntl_limb_t(-1); } else { for (long i = hiwords; i < ewords; i++) adata[i] = 0; } } if (borrow) { borrow = NTL_MPN(sub_1)(adata + ewords, bdata, nwords-ewords, 1); if (borrow) { special_carry = NTL_MPN(add_1)(adata, adata, nwords, 1); // special case: result so far is 2^n } } else { for (long i = 0; i < nwords-ewords; i++) adata[i+ewords] = bdata[i]; } sa = nwords; } else { for (long i = 0; i < ewords; i++) adata[i] = 0; for (long i = 0; i < sb; i++) adata[i+ewords] = bdata[i]; sa = ewords + sb; } } else { for (long i = 0; i < sb; i++) adata[i] = bdata[i]; sa = sb; } long here = 0; if (ebits) { if (special_carry) { NTL_MPN(sub_1)(adata, adata, nwords, (1L << ebits) - 1L); } else if (sa == nwords) { _ntl_limb_t shout = NTL_MPN(lshift)(adata, adata, sa, ebits); if (shout) { _ntl_limb_t borrow = NTL_MPN(sub_1)(adata, adata, sa, shout); if (borrow) { _ntl_limb_t carry = NTL_MPN(add_1)(adata, adata, sa, 1); if (carry) { adata[sa] = 1; sa++; } } } } else { // sa < nwords _ntl_limb_t shout = NTL_MPN(lshift)(adata, adata, sa, ebits); if (shout) { adata[sa] = shout; sa++; } } } else { if (special_carry) { adata[sa] = 1; sa++; } } STRIP(sa, adata); SIZE(*a) = sa; } void _ntl_ss_addmod(_ntl_gbigint *x, const _ntl_gbigint *a, const _ntl_gbigint *b, _ntl_gbigint p, long n) { if (((unsigned long) n) % NTL_ZZ_NBITS != 0) { _ntl_gadd(*a, *b, x); if (_ntl_gcompare(*x, p) >= 0) { _ntl_gsadd(*x, -1, x); _ntl_gswitchbit(x, n); } } else { _ntl_gadd(*a, *b, x); long sx, nwords; if (!*x || (sx = SIZE(*x)) <= (nwords = ((unsigned long) n) / NTL_ZZ_NBITS)) return; _ntl_limb_t *xdata = DATA(*x); if (xdata[nwords] == 2) { for (long i = 0; i < nwords; i++) xdata[i] = _ntl_limb_t(-1); SIZE(*x) = nwords; return; } long i = nwords-1; while (i >= 0 && xdata[i] == 0) i--; if (i < 0) return; NTL_MPN(sub_1)(xdata, xdata, nwords, 1); sx = nwords; STRIP(sx, xdata); SIZE(*x) = sx; } } void _ntl_ss_submod(_ntl_gbigint *x, const _ntl_gbigint *a, const _ntl_gbigint *b, _ntl_gbigint p, long n) { if (((unsigned long) n) % NTL_ZZ_NBITS != 0) { if (_ntl_gcompare(*a, *b) < 0) { _ntl_gadd(*a, p, x); _ntl_gsubpos(*x, *b, x); } else { _ntl_gsubpos(*a, *b, x); } } else { if (ZEROP(*b)) { _ntl_gcopy(*a, x); return; } long sb = SIZE(*b); _ntl_limb_t *bdata = DATA(*b); long sa; if (!*a) sa = 0; else sa = SIZE(*a); long nwords = ((unsigned long) n) / NTL_ZZ_NBITS; if (MustAlloc(*x, nwords+1)) _ntl_gsetlength(x, nwords+1); _ntl_limb_t *xdata = DATA(*x); if (sa >= sb) { _ntl_limb_t *adata = DATA(*a); _ntl_limb_t borrow = NTL_MPN(sub)(xdata, adata, sa, bdata, sb); if (borrow) { for (long i = sa; i < nwords; i++) xdata[i] = _ntl_limb_t(-1); _ntl_limb_t carry = NTL_MPN(add_1)(xdata, xdata, nwords, 1); if (carry) { xdata[nwords] = 1; SIZE(*x) = nwords+1; } else { long sx = nwords; STRIP(sx, xdata); SIZE(*x) = sx; } } else { long sx = sa; STRIP(sx, xdata); SIZE(*x) = sx; } } else { if (sa == 0) { xdata[0] = 1; } else { _ntl_limb_t *adata = DATA(*a); xdata[sa] = NTL_MPN(add_1)(xdata, adata, sa, 1); } for (long i = sa+1; i <= nwords; i++) xdata[i] = 0; xdata[nwords]++; _ntl_limb_t borrow = NTL_MPN(sub_n)(xdata, xdata, bdata, sb); if (borrow) { NTL_MPN(sub_1)(xdata+sb, xdata+sb, nwords+1-sb, 1); } long sx = nwords+1; STRIP(sx, xdata); SIZE(*x) = sx; } } } #endif ntl-11.5.1/src/lzz_p.cpp0000644417616742025610000002311214064716022016605 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL NTL_TLS_GLOBAL_DECL(SmartPtr, zz_pInfo_stg) NTL_CHEAP_THREAD_LOCAL zz_pInfoT *zz_pInfo = 0; SmartPtr Build_zz_pInfo(FFTPrimeInfo *info) { return MakeSmart(INIT_FFT, info); } zz_pInfoT::zz_pInfoT(long NewP, long maxroot) { if (maxroot < 0) LogicError("zz_pContext: maxroot may not be negative"); if (NewP <= 1) LogicError("zz_pContext: p must be > 1"); if (NumBits(NewP) > NTL_SP_NBITS) ResourceError("zz_pContext: modulus too big"); ZZ P, B, M, M1, MinusM; long n, i; long q, t; mulmod_t qinv; p = NewP; pinv = PrepMulMod(p); red_struct = sp_PrepRem(p); ll_red_struct = make_sp_ll_reduce_struct(p); ZZ_red_struct.build(p); p_info = 0; conv(P, p); sqr(B, P); LeftShift(B, B, maxroot+NTL_FFTFudge); set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = GetFFTPrime(n); n++; mul(M, M, q); } if (n > 4) LogicError("zz_pInit: too many primes"); NumPrimes = n; PrimeCnt = n; MaxRoot = CalcMaxRoot(q); if (maxroot < MaxRoot) MaxRoot = maxroot; negate(MinusM, M); MinusMModP = rem(MinusM, p); MinusMModPpinv = PrepMulModPrecon(MinusMModP, p, pinv); CoeffModP.SetLength(n); CoeffModPpinv.SetLength(n); x.SetLength(n); u.SetLength(n); uqinv.SetLength(n); for (i = 0; i < n; i++) { q = GetFFTPrime(i); qinv = GetFFTPrimeInv(i); div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); CoeffModP[i] = rem(M1, p); CoeffModPpinv[i] = PrepMulModPrecon(CoeffModP[i], p, pinv); x[i] = ((double) t)/((double) q); u[i] = t; uqinv[i] = PrepMulModPrecon(t, q, qinv); } } zz_pInfoT::zz_pInfoT(INIT_FFT_TYPE, FFTPrimeInfo *info) { p = info->q; pinv = info->qinv; red_struct = sp_PrepRem(p); ll_red_struct = make_sp_ll_reduce_struct(p); ZZ_red_struct.build(p); p_info = info; NumPrimes = 1; PrimeCnt = 0; MaxRoot = CalcMaxRoot(p); } // FIXME: we could make bigtab an optional argument zz_pInfoT::zz_pInfoT(INIT_USER_FFT_TYPE, long q) { long w; if (!IsFFTPrime(q, w)) LogicError("invalid user supplied prime"); p = q; pinv = PrepMulMod(p); red_struct = sp_PrepRem(p); ll_red_struct = make_sp_ll_reduce_struct(p); ZZ_red_struct.build(p); p_info_owner.make(); p_info = p_info_owner.get(); long bigtab_index = -1; #ifdef NTL_FFT_BIGTAB bigtab_index = 0; #endif InitFFTPrimeInfo(*p_info, q, w, bigtab_index); NumPrimes = 1; PrimeCnt = 0; MaxRoot = CalcMaxRoot(p); } void zz_p::init(long p, long maxroot) { zz_pContext c(p, maxroot); c.restore(); } void zz_p::FFTInit(long index) { zz_pContext c(INIT_FFT, index); c.restore(); } void zz_p::UserFFTInit(long q) { zz_pContext c(INIT_USER_FFT, q); c.restore(); } zz_pContext::zz_pContext(long p, long maxroot) : ptr(MakeSmart(p, maxroot)) { } zz_pContext::zz_pContext(INIT_FFT_TYPE, long index) { if (index < 0) LogicError("bad FFT prime index"); UseFFTPrime(index); ptr = FFTTables[index]->zz_p_context; } zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long q) : ptr(MakeSmart(INIT_USER_FFT, q)) { } void zz_pContext::save() { NTL_TLS_GLOBAL_ACCESS(zz_pInfo_stg); ptr = zz_pInfo_stg; } void zz_pContext::restore() const { NTL_TLS_GLOBAL_ACCESS(zz_pInfo_stg); zz_pInfo_stg = ptr; zz_pInfo = zz_pInfo_stg.get(); } zz_pBak::~zz_pBak() { if (MustRestore) c.restore(); } void zz_pBak::save() { c.save(); MustRestore = true; } void zz_pBak::restore() { c.restore(); MustRestore = false; } istream& operator>>(istream& s, zz_p& x) { NTL_ZZRegister(y); NTL_INPUT_CHECK_RET(s, s >> y); conv(x, y); return s; } ostream& operator<<(ostream& s, zz_p a) { NTL_ZZRegister(y); y = rep(a); s << y; return s; } // *********************************************************************** #ifdef NTL_HAVE_LL_TYPE // NOTE: the following code sequence will generate imulq // instructions on x86_64 machines, which empirically is faster // than using the mulq instruction or even the mulxq instruction, // (tested on a Haswell machine). long InnerProd_LL(const long *ap, const zz_p *bp, long n, long d, sp_ll_reduce_struct dinv) { const long BLKSIZE = (1L << min(20, 2*(NTL_BITS_PER_LONG-NTL_SP_NBITS))); unsigned long acc0 = 0; ll_type acc21; ll_init(acc21, 0); long i; for (i = 0; i <= n-BLKSIZE; i += BLKSIZE, ap += BLKSIZE, bp += BLKSIZE) { // sum ap[j]*rep(bp[j]) for j in [0..BLKSIZE) ll_type sum; ll_init(sum, 0); for (long j = 0; j < BLKSIZE; j += 4) { ll_imul_add(sum, ap[j+0], rep(bp[j+0])); ll_imul_add(sum, ap[j+1], rep(bp[j+1])); ll_imul_add(sum, ap[j+2], rep(bp[j+2])); ll_imul_add(sum, ap[j+3], rep(bp[j+3])); } ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (i < n) { // sum ap[i]*rep(bp[j]) for j in [0..n-i) ll_type sum; ll_init(sum, 0); long j = 0; for (; j <= n-i-4; j += 4) { ll_imul_add(sum, ap[j+0], rep(bp[j+0])); ll_imul_add(sum, ap[j+1], rep(bp[j+1])); ll_imul_add(sum, ap[j+2], rep(bp[j+2])); ll_imul_add(sum, ap[j+3], rep(bp[j+3])); } for (; j < n-i; j++) ll_imul_add(sum, ap[j], rep(bp[j])); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (dinv.nbits == NTL_SP_NBITS) return sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, d, dinv); else return sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, d, dinv); } long InnerProd_LL(const zz_p *ap, const zz_p *bp, long n, long d, sp_ll_reduce_struct dinv) { const long BLKSIZE = (1L << min(20, 2*(NTL_BITS_PER_LONG-NTL_SP_NBITS))); unsigned long acc0 = 0; ll_type acc21; ll_init(acc21, 0); long i; for (i = 0; i <= n-BLKSIZE; i += BLKSIZE, ap += BLKSIZE, bp += BLKSIZE) { // sum ap[j]*rep(bp[j]) for j in [0..BLKSIZE) ll_type sum; ll_init(sum, 0); for (long j = 0; j < BLKSIZE; j += 4) { ll_imul_add(sum, rep(ap[j+0]), rep(bp[j+0])); ll_imul_add(sum, rep(ap[j+1]), rep(bp[j+1])); ll_imul_add(sum, rep(ap[j+2]), rep(bp[j+2])); ll_imul_add(sum, rep(ap[j+3]), rep(bp[j+3])); } ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (i < n) { // sum ap[i]*rep(bp[j]) for j in [0..n-i) ll_type sum; ll_init(sum, 0); long j = 0; for (; j <= n-i-4; j += 4) { ll_imul_add(sum, rep(ap[j+0]), rep(bp[j+0])); ll_imul_add(sum, rep(ap[j+1]), rep(bp[j+1])); ll_imul_add(sum, rep(ap[j+2]), rep(bp[j+2])); ll_imul_add(sum, rep(ap[j+3]), rep(bp[j+3])); } for (; j < n-i; j++) ll_imul_add(sum, rep(ap[j]), rep(bp[j])); ll_add(sum, acc0); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); } if (dinv.nbits == NTL_SP_NBITS) return sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, d, dinv); else return sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, d, dinv); } long InnerProd_L(const long *ap, const zz_p *bp, long n, long d, sp_reduce_struct dinv, long bound) { unsigned long sum = 0; long j = 0; if (n <= bound) { for (; j <= n-4; j += 4) { sum += (ap[j+0]) * rep(bp[j+0]); sum += (ap[j+1]) * rep(bp[j+1]); sum += (ap[j+2]) * rep(bp[j+2]); sum += (ap[j+3]) * rep(bp[j+3]); } for (; j < n; j++) sum += (ap[j]) * rep(bp[j]); return rem(sum, d, dinv); } for (; j <= n-bound; j += bound) { long i = 0; for (; i <= bound-4; i += 4) { sum += (ap[j+i+0]) * rep(bp[j+i+0]); sum += (ap[j+i+1]) * rep(bp[j+i+1]); sum += (ap[j+i+2]) * rep(bp[j+i+2]); sum += (ap[j+i+3]) * rep(bp[j+i+3]); } for (; i < bound; i++) { sum += (ap[j+i]) * rep(bp[j+i]); } sum = rem(sum, d, dinv); } if (j >= n) return sum; for (; j <= n-4; j += 4) { sum += (ap[j+0]) * rep(bp[j+0]); sum += (ap[j+1]) * rep(bp[j+1]); sum += (ap[j+2]) * rep(bp[j+2]); sum += (ap[j+3]) * rep(bp[j+3]); } for (; j < n; j++) sum += (ap[j]) * rep(bp[j]); return rem(sum, d, dinv); } long InnerProd_L(const zz_p *ap, const zz_p *bp, long n, long d, sp_reduce_struct dinv, long bound) { unsigned long sum = 0; long j = 0; if (n <= bound) { for (; j <= n-4; j += 4) { sum += rep(ap[j+0]) * rep(bp[j+0]); sum += rep(ap[j+1]) * rep(bp[j+1]); sum += rep(ap[j+2]) * rep(bp[j+2]); sum += rep(ap[j+3]) * rep(bp[j+3]); } for (; j < n; j++) sum += rep(ap[j]) * rep(bp[j]); return rem(sum, d, dinv); } for (; j <= n-bound; j += bound) { long i = 0; for (; i <= bound-4; i += 4) { sum += rep(ap[j+i+0]) * rep(bp[j+i+0]); sum += rep(ap[j+i+1]) * rep(bp[j+i+1]); sum += rep(ap[j+i+2]) * rep(bp[j+i+2]); sum += rep(ap[j+i+3]) * rep(bp[j+i+3]); } for (; i < bound; i++) { sum += rep(ap[j+i]) * rep(bp[j+i]); } sum = rem(sum, d, dinv); } if (j >= n) return sum; for (; j <= n-4; j += 4) { sum += rep(ap[j+0]) * rep(bp[j+0]); sum += rep(ap[j+1]) * rep(bp[j+1]); sum += rep(ap[j+2]) * rep(bp[j+2]); sum += rep(ap[j+3]) * rep(bp[j+3]); } for (; j < n; j++) sum += rep(ap[j]) * rep(bp[j]); return rem(sum, d, dinv); } #endif NTL_END_IMPL ntl-11.5.1/src/lzz_pE.cpp0000644417616742025610000000404714064716022016720 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL NTL_TLS_GLOBAL_DECL(SmartPtr, zz_pEInfo_stg) NTL_CHEAP_THREAD_LOCAL zz_pEInfoT *zz_pEInfo = 0; zz_pEInfoT::zz_pEInfoT(const zz_pX& NewP) { build(p, NewP); _card_base = zz_p::modulus(); _card_exp = deg(NewP); } const ZZ& zz_pE::cardinality() { if (!zz_pEInfo) LogicError("zz_pE::cardinality: undefined modulus"); do { // NOTE: thread safe lazy init Lazy::Builder builder(zz_pEInfo->_card); if (!builder()) break; UniquePtr p; p.make(); power(*p, zz_pEInfo->_card_base, zz_pEInfo->_card_exp); builder.move(p); } while (0); return *zz_pEInfo->_card; } void zz_pE::init(const zz_pX& p) { zz_pEContext c(p); c.restore(); } void zz_pEContext::save() { NTL_TLS_GLOBAL_ACCESS(zz_pEInfo_stg); ptr = zz_pEInfo_stg; } void zz_pEContext::restore() const { NTL_TLS_GLOBAL_ACCESS(zz_pEInfo_stg); zz_pEInfo_stg = ptr; zz_pEInfo = zz_pEInfo_stg.get(); } zz_pEBak::~zz_pEBak() { if (MustRestore) c.restore(); } void zz_pEBak::save() { c.save(); MustRestore = true; } void zz_pEBak::restore() { c.restore(); MustRestore = false; } const zz_pE& zz_pE::zero() { static const zz_pE z(INIT_NO_ALLOC); // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, zz_pE& x) { zz_pX y; NTL_INPUT_CHECK_RET(s, s >> y); conv(x, y); return s; } void div(zz_pE& x, const zz_pE& a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void div(zz_pE& x, const zz_pE& a, long b) { NTL_zz_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(zz_pE& x, const zz_pE& a, const zz_p& b) { NTL_zz_pRegister(B); B = b; inv(B, B); mul(x, a, B); } void div(zz_pE& x, long a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void div(zz_pE& x, const zz_p& a, const zz_pE& b) { zz_pE t; inv(t, b); mul(x, a, t); } void inv(zz_pE& x, const zz_pE& a) { InvMod(x._zz_pE__rep, a._zz_pE__rep, zz_pE::modulus()); } NTL_END_IMPL ntl-11.5.1/src/lzz_pEX.cpp0000644417616742025610000017725514064716022017064 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL const zz_pEX& zz_pEX::zero() { static const zz_pEX z; // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, zz_pEX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const zz_pEX& a) { return s << a.rep; } void zz_pEX::normalize() { long n; const zz_pE* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const zz_pEX& a) { return a.rep.length() == 0; } long IsOne(const zz_pEX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } long operator==(const zz_pEX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; NTL_zz_pRegister(bb); bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const zz_pEX& a, const zz_p& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } long operator==(const zz_pEX& a, const zz_pE& b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void SetCoeff(zz_pEX& x, long i, const zz_pE& a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { /* careful: a may alias a coefficient of x */ long alloc = x.rep.allocated(); if (alloc > 0 && i >= alloc) { zz_pE aa = a; x.rep.SetLength(i+1); x.rep[i] = aa; } else { x.rep.SetLength(i+1); x.rep[i] = a; } for (j = m+1; j < i; j++) clear(x.rep[j]); } else x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pEX& x, long i, const zz_p& aa) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); NTL_zz_pRegister(a); // watch out for aliases! a = aa; m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pEX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else { NTL_zz_pRegister(T); T = a; SetCoeff(x, i, T); } } void SetCoeff(zz_pEX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(zz_pEX& x) { clear(x); SetCoeff(x, 1); } long IsX(const zz_pEX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const zz_pE& coeff(const zz_pEX& a, long i) { if (i < 0 || i > deg(a)) return zz_pE::zero(); else return a.rep[i]; } const zz_pE& LeadCoeff(const zz_pEX& a) { if (IsZero(a)) return zz_pE::zero(); else return a.rep[deg(a)]; } const zz_pE& ConstTerm(const zz_pEX& a) { if (IsZero(a)) return zz_pE::zero(); else return a.rep[0]; } void conv(zz_pEX& x, const zz_pE& a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(zz_pEX& x, long a) { if (a == 0) clear(x); else if (a == 1) set(x); else { NTL_zz_pRegister(T); T = a; conv(x, T); } } void conv(zz_pEX& x, const ZZ& a) { NTL_zz_pRegister(T); conv(T, a); conv(x, T); } void conv(zz_pEX& x, const zz_p& a) { if (IsZero(a)) clear(x); else if (IsOne(a)) set(x); else { x.rep.SetLength(1); conv(x.rep[0], a); x.normalize(); } } void conv(zz_pEX& x, const zz_pX& aa) { zz_pX a = aa; // in case a aliases the rep of a coefficient of x long n = deg(a)+1; long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], coeff(a, i)); } void conv(zz_pEX& x, const vec_zz_pE& a) { x.rep = a; x.normalize(); } /* additional legacy conversions for v6 conversion regime */ void conv(zz_pEX& x, const ZZX& a) { long n = a.rep.length(); long i; x.rep.SetLength(n); for (i = 0; i < n; i++) conv(x.rep[i], a.rep[i]); x.normalize(); } /* ------------------------------------- */ void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_pE *ap, *bp; zz_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) add(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(zz_pEX& x, const zz_pEX& a, const zz_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (&x == &a) { add(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; add(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); add(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void add(zz_pEX& x, const zz_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_pE *ap, *bp; zz_pE* xp; for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) sub(*xp, (*ap), (*bp)); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) negate(*xp, *bp); else x.normalize(); } void sub(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, const zz_p& b) { long n = a.rep.length(); if (n == 0) { conv(x, b); negate(x, x); } else if (&x == &a) { sub(x.rep[0], a.rep[0], b); x.normalize(); } else if (x.rep.MaxLength() == 0) { x = a; sub(x.rep[0], a.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], a.rep[0], b); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void sub(zz_pEX& x, const zz_pEX& a, long b) { if (a.rep.length() == 0) { conv(x, b); negate(x, x); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pEX& x, const zz_pE& b, const zz_pEX& a) { long n = a.rep.length(); if (n == 0) { conv(x, b); } else if (x.rep.MaxLength() == 0) { negate(x, a); add(x.rep[0], x.rep[0], b); x.normalize(); } else { // ugly...b could alias a coeff of x zz_pE *xp = x.rep.elts(); sub(xp[0], b, a.rep[0]); x.rep.SetLength(n); xp = x.rep.elts(); const zz_pE *ap = a.rep.elts(); long i; for (i = 1; i < n; i++) negate(xp[i], ap[i]); x.normalize(); } } void sub(zz_pEX& x, const zz_p& a, const zz_pEX& b) { NTL_zz_pRegister(T); // avoids aliasing problems T = a; negate(x, b); add(x, x, T); } void sub(zz_pEX& x, long a, const zz_pEX& b) { NTL_zz_pRegister(T); T = a; negate(x, b); add(x, x, T); } void mul(zz_pEX& c, const zz_pEX& a, const zz_pEX& b) { if (&a == &b) { sqr(c, a); return; } if (IsZero(a) || IsZero(b)) { clear(c); return; } if (deg(a) == 0) { mul(c, b, ConstTerm(a)); return; } if (deg(b) == 0) { mul(c, a, ConstTerm(b)); return; } // general case...Kronecker subst zz_pX A, B, C; long da = deg(a); long db = deg(b); long n = zz_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(da+db+1, n2, 0)) ResourceError("overflow in zz_pEX mul"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const zz_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); B.rep.SetLength((db+1)*n2); for (i = 0; i <= db; i++) { const zz_pX& coeff = rep(b.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) B.rep[n2*i + j] = coeff.rep[j]; } B.normalize(); mul(C, A, B); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); zz_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, const zz_pE& b) { if (IsZero(b)) { clear(x); return; } zz_pE t; t = b; long i, da; const zz_pE *ap; zz_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, const zz_p& b) { if (IsZero(b)) { clear(x); return; } NTL_zz_pRegister(t); t = b; long i, da; const zz_pE *ap; zz_pE* xp; da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) mul(xp[i], ap[i], t); x.normalize(); } void mul(zz_pEX& x, const zz_pEX& a, long b) { NTL_zz_pRegister(t); t = b; mul(x, a, t); } void sqr(zz_pEX& c, const zz_pEX& a) { if (IsZero(a)) { clear(c); return; } if (deg(a) == 0) { zz_pE res; sqr(res, ConstTerm(a)); conv(c, res); return; } // general case...Kronecker subst zz_pX A, C; long da = deg(a); long n = zz_pE::degree(); long n2 = 2*n-1; if (NTL_OVERFLOW(2*da+1, n2, 0)) ResourceError("overflow in zz_pEX sqr"); long i, j; A.rep.SetLength((da+1)*n2); for (i = 0; i <= da; i++) { const zz_pX& coeff = rep(a.rep[i]); long dcoeff = deg(coeff); for (j = 0; j <= dcoeff; j++) A.rep[n2*i + j] = coeff.rep[j]; } A.normalize(); sqr(C, A); long Clen = C.rep.length(); long lc = (Clen + n2 - 1)/n2; long dc = lc - 1; c.rep.SetLength(dc+1); zz_pX tmp; for (i = 0; i <= dc; i++) { tmp.rep.SetLength(n2); for (j = 0; j < n2 && n2*i + j < Clen; j++) tmp.rep[j] = C.rep[n2*i + j]; for (; j < n2; j++) clear(tmp.rep[j]); tmp.normalize(); conv(c.rep[i], tmp); } c.normalize(); } void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n) { if (n < 0) LogicError("MulTrunc: bad args"); zz_pEX t; mul(t, a, b); trunc(x, t, n); } void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n) { if (n < 0) LogicError("SqrTrunc: bad args"); zz_pEX t; sqr(t, a); trunc(x, t, n); } void CopyReverse(zz_pEX& x, const zz_pEX& a, long hi) // x[0..hi] = reverse(a[0..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi+1; m = a.rep.length(); x.rep.SetLength(n); const zz_pE* ap = a.rep.elts(); zz_pE* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void trunc(zz_pEX& x, const zz_pEX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; zz_pE* xp; const zz_pE* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void random(zz_pEX& x, long n) { long i; x.rep.SetLength(n); for (i = 0; i < n; i++) random(x.rep[i]); x.normalize(); } void negate(zz_pEX& x, const zz_pEX& a) { long n = a.rep.length(); x.rep.SetLength(n); const zz_pE* ap = a.rep.elts(); zz_pE* xp = x.rep.elts(); long i; for (i = n; i; i--, ap++, xp++) negate((*xp), (*ap)); } static void MulByXModAux(zz_pEX& h, const zz_pEX& a, const zz_pEX& f) { long i, n, m; zz_pE* hh; const zz_pE *aa, *ff; zz_pE t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(zz_pEX& h, const zz_pEX& a, const zz_pEX& f) { if (&h == &f) { zz_pEX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void PlainMul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { long da = deg(a); long db = deg(b); if (da < 0 || db < 0) { clear(x); return; } long d = da+db; const zz_pE *ap, *bp; zz_pE *xp; zz_pEX la, lb; if (&x == &a) { la = a; ap = la.rep.elts(); } else ap = a.rep.elts(); if (&x == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); x.rep.SetLength(d+1); xp = x.rep.elts(); long i, j, jmin, jmax; zz_pX t, accum; for (i = 0; i <= d; i++) { jmin = max(0, i-db); jmax = min(da, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, rep(ap[j]), rep(bp[i-j])); add(accum, accum, t); } conv(xp[i], accum); } x.normalize(); } void SetSize(vec_zz_pX& x, long n, long m) { x.SetLength(n); long i; for (i = 0; i < n; i++) x[i].rep.SetMaxLength(m); } void PlainDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da+1, 2*zz_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b, vec_zz_pX& x) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b, vec_zz_pX& x) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pEX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void PlainDiv(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pE *qp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pEX: division by zero"); if (da < db) { clear(q); return; } zz_pEX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da+1-db, 2*zz_pE::degree()); for (i = db; i <= da; i++) x[i-db] = rep(a.rep[i]); xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); for (i = dq; i >= 0; i--) { conv(t, xp[i]); if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j-db], xp[i+j-db], s); } } } void PlainRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long da, db, dq, i, j, LCIsOne; const zz_pE *bp; zz_pX *xp; zz_pE LCInv, t; zz_pX s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pEX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_pX x; SetSize(x, da + 1, 2*zz_pE::degree()); for (i = 0; i <= da; i++) x[i] = rep(a.rep[i]); xp = x.elts(); dq = da - db; for (i = dq; i >= 0; i--) { conv(t, xp[i+db]); if (!LCIsOne) mul(t, t, LCInv); negate(t, t); for (j = db-1; j >= 0; j--) { mul(s, rep(t), rep(bp[j])); add(xp[i+j], xp[i+j], s); } } r.rep.SetLength(db); for (i = 0; i < db; i++) conv(r.rep[i], xp[i]); r.normalize(); } void RightShift(zz_pEX& x, const zz_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(zz_pEX& x, const zz_pEX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void NewtonInv(zz_pEX& c, const zz_pEX& a, long e) { zz_pE x; inv(x, ConstTerm(a)); if (e == 1) { conv(c, x); return; } vec_long E; E.SetLength(0); append(E, e); while (e > 1) { e = (e+1)/2; append(E, e); } long L = E.length(); zz_pEX g, g0, g1, g2; g.rep.SetMaxLength(E[0]); g0.rep.SetMaxLength(E[0]); g1.rep.SetMaxLength((3*E[0]+1)/2); g2.rep.SetMaxLength(E[0]); conv(g, x); long i; for (i = L-1; i > 0; i--) { // lift from E[i] to E[i-1] long k = E[i]; long l = E[i-1]-E[i]; trunc(g0, a, k+l); mul(g1, g0, g); RightShift(g1, g1, k); trunc(g1, g1, l); mul(g2, g1, g); trunc(g2, g2, l); LeftShift(g2, g2, k); sub(g, g, g2); } c = g; } void InvTrunc(zz_pEX& c, const zz_pEX& a, long e) { if (e < 0) LogicError("InvTrunc: bad args"); if (e == 0) { clear(c); return; } if (NTL_OVERFLOW(e, 1, 0)) ResourceError("overflow in InvTrunc"); NewtonInv(c, a, e); } const long zz_pEX_MOD_PLAIN = 0; const long zz_pEX_MOD_MUL = 1; void build(zz_pEXModulus& F, const zz_pEX& f) { long n = deg(f); if (n <= 0) LogicError("build(zz_pEXModulus,zz_pEX): deg(f) <= 0"); if (NTL_OVERFLOW(n, zz_pE::degree(), 0)) ResourceError("build(zz_pEXModulus,zz_pEX): overflow"); F.tracevec.make(); F.f = f; F.n = n; if (F.n < zz_pE::ModCross()) { F.method = zz_pEX_MOD_PLAIN; } else { F.method = zz_pEX_MOD_MUL; zz_pEX P1; zz_pEX P2; CopyReverse(P1, f, n); InvTrunc(P2, P1, n-1); CopyReverse(P1, P2, n-2); trunc(F.h0, P1, n-2); trunc(F.f0, f, n); F.hlc = ConstTerm(P2); } } zz_pEXModulus::zz_pEXModulus() { n = -1; method = zz_pEX_MOD_PLAIN; } zz_pEXModulus::~zz_pEXModulus() { } zz_pEXModulus::zz_pEXModulus(const zz_pEX& ff) { n = -1; method = zz_pEX_MOD_PLAIN; build(*this, ff); } void UseMulRem21(zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); } void UseMulDivRem21(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); mul(P1, P2, F.f0); trunc(P1, P1, F.n); trunc(r, a, F.n); sub(r, r, P1); q = P2; } void UseMulDiv21(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX P1; zz_pEX P2; RightShift(P1, a, F.n); mul(P2, P1, F.h0); RightShift(P2, P2, F.n-2); if (!IsOne(F.hlc)) mul(P1, P1, F.hlc); add(P2, P2, P1); q = P2; } void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainRem(x, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulRem21(x, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulRem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainDivRem(q, r, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDivRem21(q, r, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); zz_pEX qbuf(INIT_SIZE, n-1); zz_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); UseMulDivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainDiv(q, a, F.f); return; } long da = deg(a); long n = F.n; if (da <= 2*n-2) { UseMulDiv21(q, a, F); return; } zz_pEX buf(INIT_SIZE, 2*n-1); zz_pEX qbuf(INIT_SIZE, n-1); zz_pEX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) UseMulDivRem21(qbuf, buf, buf, F); else UseMulDiv21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(zz_pEX& c, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F) { if (deg(a) >= F.n || deg(b) >= F.n) LogicError("MulMod: bad args"); zz_pEX t; mul(t, a, b); rem(c, t, F); } void SqrMod(zz_pEX& c, const zz_pEX& a, const zz_pEXModulus& F) { if (deg(a) >= F.n) LogicError("MulMod: bad args"); zz_pEX t; sqr(t, a); rem(c, t, F); } void UseMulRem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; } void UseMulDivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); mul(P1, P2, b); sub(P1, a, P1); r = P1; q = P2; } void UseMulDiv(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { zz_pEX P1; zz_pEX P2; long da = deg(a); long db = deg(b); CopyReverse(P1, b, db); InvTrunc(P2, P1, da-db+1); CopyReverse(P1, P2, da-db); RightShift(P2, a, db); mul(P2, P1, P2); RightShift(P2, P2, da-db); q = P2; } void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainDivRem(q, r, a, b); else if (sa < 4*sb) UseMulDivRem(q, r, a, b); else { zz_pEXModulus B; build(B, b); DivRem(q, r, a, B); } } void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainDiv(q, a, b); else if (sa < 4*sb) UseMulDiv(q, a, b); else { zz_pEXModulus B; build(B, b); div(q, a, B); } } void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b) { zz_pE T; inv(T, b); mul(q, a, T); } void div(zz_pEX& q, const zz_pEX& a, const zz_p& b) { NTL_zz_pRegister(T); inv(T, b); mul(q, a, T); } void div(zz_pEX& q, const zz_pEX& a, long b) { NTL_zz_pRegister(T); T = b; inv(T, T); mul(q, a, T); } void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sb < zz_pE::DivCross() || sa-sb < zz_pE::DivCross()) PlainRem(r, a, b); else if (sa < 4*sb) UseMulRem(r, a, b); else { zz_pEXModulus B; build(B, b); rem(r, a, B); } } void PlainGCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b) { zz_pE t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; zz_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_zz_pX tmp; SetSize(tmp, n, 2*zz_pE::degree()); u = a; v = b; do { PlainRem(u, u, v, tmp); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } class _NTL_zz_pEXMatrix { private: _NTL_zz_pEXMatrix(const _NTL_zz_pEXMatrix&); // disable zz_pEX elts[2][2]; public: _NTL_zz_pEXMatrix() { } ~_NTL_zz_pEXMatrix() { } void operator=(const _NTL_zz_pEXMatrix&); zz_pEX& operator() (long i, long j) { return elts[i][j]; } const zz_pEX& operator() (long i, long j) const { return elts[i][j]; } }; void _NTL_zz_pEXMatrix::operator=(const _NTL_zz_pEXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } static void mul(zz_pEX& U, zz_pEX& V, const _NTL_zz_pEXMatrix& M) // (U, V)^T = M*(U, V)^T { zz_pEX t1, t2, t3; mul(t1, M(0,0), U); mul(t2, M(0,1), V); add(t3, t1, t2); mul(t1, M(1,0), U); mul(t2, M(1,1), V); add(V, t1, t2); U = t3; } static void mul(_NTL_zz_pEXMatrix& A, _NTL_zz_pEXMatrix& B, _NTL_zz_pEXMatrix& C) // A = B*C, B and C are destroyed { zz_pEX t1, t2; mul(t1, B(0,0), C(0,0)); mul(t2, B(0,1), C(1,0)); add(A(0,0), t1, t2); mul(t1, B(1,0), C(0,0)); mul(t2, B(1,1), C(1,0)); add(A(1,0), t1, t2); mul(t1, B(0,0), C(0,1)); mul(t2, B(0,1), C(1,1)); add(A(0,1), t1, t2); mul(t1, B(1,0), C(0,1)); mul(t2, B(1,1), C(1,1)); add(A(1,1), t1, t2); long i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { B(i,j).kill(); C(i,j).kill(); } } } void IterHalfGCD(_NTL_zz_pEXMatrix& M_out, zz_pEX& U, zz_pEX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; zz_pEX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } #define NTL_zz_pEX_HalfGCD_CROSSOVER (25) #define NTL_zz_pEX_GCD_CROSSOVER (275) void HalfGCD(_NTL_zz_pEXMatrix& M_out, const zz_pEX& U, const zz_pEX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; zz_pEX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_zz_pEX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_zz_pEXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } zz_pEX Q; _NTL_zz_pEXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); zz_pEX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(_NTL_zz_pEXMatrix& M_out, zz_pEX& U, zz_pEX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_zz_pEX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_zz_pEXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } zz_pEX Q; _NTL_zz_pEXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); zz_pEX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(zz_pEX& U, zz_pEX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; _NTL_zz_pEXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); zz_pEX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(zz_pEX& d, const zz_pEX& u, const zz_pEX& v) { zz_pEX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_zz_pEX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b) { zz_pE w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } zz_pEX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } _NTL_zz_pEXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(zz_pE* a, long n) { long i, k; zz_pE b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a) { long n = a.length(); if (n == 0) { set(x); return; } x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); } void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a) // does a Horner evaluation { zz_pE acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_zz_pE bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b) { long m = a.length(); if (b.length() != m) LogicError("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_zz_pE prod; prod = a; zz_pE t1, t2; long k, i; vec_zz_pE res; res.SetLength(m); for (k = 0; k < m; k++) { const zz_pE& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(zz_pEX& x, const vec_zz_pE& v, long low, long high, const vec_zz_pEX& H, long n, vec_zz_pX& t) { zz_pX s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_pE& h = H[i-low].rep; long m = h.length(); const zz_pX& w = rep(v[i]); for (j = 0; j < m; j++) { mul(s, w, rep(h[j])); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) conv(x.rep[j], t[j]); x.normalize(); } void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { if (deg(g) <= 0) { x = g; return; } zz_pEX s, t; vec_zz_pX scratch; SetSize(scratch, deg(F), 2*zz_pE::degree()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const zz_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(zz_pEXArgument& A, const zz_pEX& h, const zz_pEXModulus& F, long m) { long i; if (m <= 0 || deg(h) >= F.n) LogicError("build: bad args"); if (m > F.n) m = F.n; if (zz_pEXArgBound > 0) { double sz = zz_p::storage(); sz = sz*zz_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_p); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_pE); sz = sz/1024; m = min(m, long(zz_pEXArgBound/sz)); m = max(m, 1); } A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], h, F); } NTL_CHEAP_THREAD_LOCAL long zz_pEXArgBound = 0; void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pEXArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } zz_pEXArgument A; build(A, h, F, m); zz_pEX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } zz_pEXArgument A; build(A, h, F, m); zz_pEX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); zz_pEX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, db); } void TransMulMod(zz_pEX& x, const zz_pEX& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); zz_pEX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void ShiftSub(zz_pEX& U, const zz_pEX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { zz_pEX xx; TransMulMod(xx, to_zz_pEX(a), B, F); x = xx.rep; } static void ProjectPowers(vec_zz_pE& x, const zz_pEX& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { if (k < 0 || deg(a) >= F.n) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pEXTransMultiplier M; build(M, H.H[m], F); zz_pEX s; s = a; x.SetLength(k); long i; for (i = 0; i <= l; i++) { long m1 = min(m, k-i*m); for (long j = 0; j < m1; j++) InnerProduct(x[i*m+j], H.H[j].rep, s.rep); if (i < l) TransMulMod(s, s, M, F); } } static void ProjectPowers(vec_zz_pE& x, const zz_pEX& a, long k, const zz_pEX& h, const zz_pEXModulus& F) { if (k < 0 || deg(a) >= F.n || deg(h) >= F.n) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0);; return; } long m = SqrRoot(k); zz_pEXArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { ProjectPowers(x, to_zz_pEX(a), k, H, F); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F) { ProjectPowers(x, to_zz_pEX(a), k, h, F); } void BerlekampMassey(zz_pEX& h, const vec_zz_pE& a, long m) { zz_pEX Lambda, Sigma, Temp; long L; zz_pE Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); BerlekampMassey(h, a, m); } void DoMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const zz_pEX& R) { vec_zz_pE x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); zz_pEX R; random(R, n); DoMinPolyMod(h, g, F, m, R); } void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ zz_pEX h2, h3; zz_pEX R; zz_pEXTransMultiplier H1; for (;;) { random(R, n); build(H1, h1, F); TransMulMod(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); zz_pEX R; set(R); DoMinPolyMod(h, g, F, m, R); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F) { IrredPolyMod(h, g, F, F.n); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F) { MinPolyMod(hh, g, F, F.n); } void diff(zz_pEX& x, const zz_pEX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(zz_pEX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; zz_pE t; inv(t, LeadCoeff(x)); mul(x, x, t); } long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } zz_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const zz_pEX& a, const zz_pEX& b) { if (IsZero(b)) return IsZero(a); zz_pEX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } static long OptWinSize(long n) // finds k that minimizes n/(k+1) + 2^{k-1} { long k; double v, v_new; v = n/2.0 + 1.0; k = 1; for (;;) { v_new = n/(double(k+2)) + double(1L << k); if (v_new >= v) break; v = v_new; k++; } return k; } void PowerMod(zz_pEX& h, const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F) // h = g^e mod f using "sliding window" algorithm { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (e == 0) { set(h); return; } if (e == 1) { h = g; return; } if (e == -1) { InvMod(h, g, F); return; } if (e == 2) { SqrMod(h, g, F); return; } if (e == -2) { SqrMod(h, g, F); InvMod(h, h, F); return; } long n = NumBits(e); zz_pEX res; res.SetMaxLength(F.n); set(res); long i; if (n < 16) { // plain square-and-multiply algorithm for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, g, F); } if (e < 0) InvMod(res, res, F); h = res; return; } long k = OptWinSize(n); k = min(k, 3); vec_zz_pEX v; v.SetLength(1L << (k-1)); v[0] = g; if (k > 1) { zz_pEX t; SqrMod(t, g, F); for (i = 1; i < (1L << (k-1)); i++) MulMod(v[i], v[i-1], t, F); } long val; long cnt; long m; val = 0; for (i = n-1; i >= 0; i--) { val = (val << 1) | bit(e, i); if (val == 0) SqrMod(res, res, F); else if (val >= (1L << (k-1)) || i == 0) { cnt = 0; while ((val & 1) == 0) { val = val >> 1; cnt++; } m = val; while (m > 0) { SqrMod(res, res, F); m = m >> 1; } MulMod(res, res, v[val >> 1], F); while (cnt > 0) { SqrMod(res, res, F); cnt--; } val = 0; } } if (e < 0) InvMod(res, res, F); h = res; } void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); zz_pEX d, xx, t; XGCD(d, xx, t, a, f); if (!IsOne(d)) InvModError("zz_pEX InvMod: can't compute multiplicative inverse"); x = xx; } long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvModStatus: bad args"); zz_pEX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) LogicError("MulMod: bad args"); zz_pEX t; mul(t, a, b); rem(x, t, f); } void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("SqrMod: bad args"); zz_pEX t; sqr(t, a); rem(x, t, f); } void PowerXMod(zz_pEX& hh, const ZZ& e, const zz_pEXModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; zz_pEX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void reverse(zz_pEX& x, const zz_pEX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { zz_pEX tmp; CopyReverse(tmp, a, hi); x = tmp; } else CopyReverse(x, a, hi); } void power(zz_pEX& x, const zz_pEX& a, long e) { if (e < 0) { ArithmeticError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); zz_pEX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } static void FastTraceVec(vec_zz_pE& S, const zz_pEXModulus& f) { long n = deg(f); zz_pEX x = reverse(-LeftShift(reverse(diff(reverse(f)), n-1), n-1)/f, n-1); S.SetLength(n); S[0] = n; long i; for (i = 1; i < n; i++) S[i] = coeff(x, i); } void PlainTraceVec(vec_zz_pE& S, const zz_pEX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); zz_pEX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; zz_pX acc, t; zz_pE t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } } void TraceVec(vec_zz_pE& S, const zz_pEX& f) { if (deg(f) < zz_pE::DivCross()) PlainTraceVec(S, f); else FastTraceVec(S, f); } static void ComputeTraceVec(vec_zz_pE& S, const zz_pEXModulus& F) { if (F.method == zz_pEX_MOD_PLAIN) { PlainTraceVec(S, F.f); } else { FastTraceVec(S, F); } } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); InnerProduct(x, a.rep, *F.tracevec.val()); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b) { zz_pE res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; zz_pE lc; set(res); long n = max(deg(a),deg(b)) + 1; zz_pEX u(INIT_SIZE, n), v(INIT_SIZE, n); vec_zz_pX tmp; SetSize(tmp, n, 2*zz_pE::degree()); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v, tmp); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void resultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b) { PlainResultant(rres, a, b); } void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } zz_pE t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { zz_pE t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } // tower stuff... void InnerProduct(zz_pEX& x, const vec_zz_p& v, long low, long high, const vec_zz_pEX& H, long n, vec_zz_pE& t) { zz_pE s; long i, j; for (j = 0; j < n; j++) clear(t[j]); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_pE& h = H[i-low].rep; long m = h.length(); const zz_p& w = v[i]; for (j = 0; j < m; j++) { mul(s, h[j], w); add(t[j], t[j], s); } } x.rep.SetLength(n); for (j = 0; j < n; j++) x.rep[j] = t[j]; x.normalize(); } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { if (deg(g) <= 0) { conv(x, g); return; } zz_pEX s, t; vec_zz_pE scratch; scratch.SetLength(deg(F)); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; const zz_pEX& M = A.H[m]; InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pEXArgument A; build(A, h, F, m); CompTower(x, g, A, F); } void PrepareProjection(vec_vec_zz_p& tt, const vec_zz_pE& s, const vec_zz_p& proj) { long l = s.length(); tt.SetLength(l); zz_pXMultiplier M; long i; for (i = 0; i < l; i++) { build(M, rep(s[i]), zz_pE::modulus()); UpdateMap(tt[i], proj, M, zz_pE::modulus()); } } void ProjectedInnerProduct(zz_p& x, const vec_zz_pE& a, const vec_vec_zz_p& b) { long n = min(a.length(), b.length()); zz_p t, res; res = 0; long i; for (i = 0; i < n; i++) { project(t, b[i], rep(a[i])); res += t; } x = res; } void PrecomputeProj(vec_zz_p& proj, const zz_pX& f) { long n = deg(f); if (n <= 0) LogicError("PrecomputeProj: bad args"); if (ConstTerm(f) != 0) { proj.SetLength(1); proj[0] = 1; } else { proj.SetLength(n); clear(proj); proj[n-1] = 1; } } void ProjectPowersTower(vec_zz_p& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F, const vec_zz_p& proj) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pEXTransMultiplier M; build(M, H.H[m], F); vec_zz_pE s(INIT_SIZE, n); s = a; x.SetLength(k); vec_vec_zz_p tt; for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); zz_p* w = &x[i*m]; PrepareProjection(tt, s, proj); for (long j = 0; j < m1; j++) ProjectedInnerProduct(w[j], H.H[j].rep, tt); if (i < l) UpdateMap(s, s, M, F); } } void ProjectPowersTower(vec_zz_p& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F, const vec_zz_p& proj) { if (a.length() > F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); zz_pEXArgument H; build(H, h, F, m); ProjectPowersTower(x, a, k, H, F, proj); } void DoMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const vec_zz_pE& R, const vec_zz_p& proj) { vec_zz_p x; ProjectPowersTower(x, R, 2*m, g, F, proj); MinPolySeq(h, x, m); } void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { long n = F.n; if (m < 1 || m > n*zz_pE::degree()) LogicError("ProbMinPoly: bad args"); vec_zz_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); vec_zz_p proj; PrecomputeProj(proj, zz_pE::modulus()); DoMinPolyTower(h, g, F, m, R, proj); } void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m, const vec_zz_p& proj) { long n = F.n; if (m < 1 || m > n*zz_pE::degree()) LogicError("ProbMinPoly: bad args"); vec_zz_pE R; R.SetLength(n); long i; for (i = 0; i < n; i++) random(R[i]); DoMinPolyTower(h, g, F, m, R, proj); } void MinPolyTower(zz_pX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX h; zz_pEX h1; long n = F.n; if (m < 1 || m > n*zz_pE::degree()) { LogicError("MinPoly: bad args"); } vec_zz_p proj; PrecomputeProj(proj, zz_pE::modulus()); /* probabilistically compute min-poly */ ProbMinPolyTower(h, g, F, m, proj); if (deg(h) == m) { hh = h; return; } CompTower(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; zz_pX h2; zz_pEX h3; vec_zz_pE R; zz_pEXTransMultiplier H1; for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyTower(h2, g, F, m-deg(h), R, proj); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompTower(h3, h2, g, F); MulMod(h1, h3, h1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m) { if (m < 1 || m > deg(F)*zz_pE::degree()) LogicError("IrredPoly: bad args"); vec_zz_pE R; R.SetLength(1); R[0] = 1; vec_zz_p proj; proj.SetLength(1); proj[0] = 1; DoMinPolyTower(h, g, F, m, R, proj); } NTL_END_IMPL ntl-11.5.1/src/lzz_pEXFactoring.cpp0000644417616742025610000006671614064716022020720 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static void IterPower(zz_pE& c, const zz_pE& a, long n) { zz_pE res; long i; res = a; for (i = 0; i < n; i++) power(res, res, zz_p::modulus()); c = res; } void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& ff) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SquareFreeDecomp: bad args"); zz_pEX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long k, d; long p = to_long(zz_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) IterPower(f.rep[k], r.rep[k*p], zz_pE::degree()-1); m = m*p; } } while (!finished); } static void AbsTraceMap(zz_pEX& h, const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX res, tmp; long k = NumBits(zz_pE::cardinality())-1; res = a; tmp = a; long i; for (i = 0; i < k-1; i++) { SqrMod(tmp, tmp, F); add(res, res, tmp); } h = res; } void FrobeniusMap(zz_pEX& h, const zz_pEXModulus& F) { PowerXMod(h, zz_pE::cardinality(), F); } static void RecFindRoots(vec_zz_pE& x, const zz_pEX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } zz_pEX h; zz_pEX r; { zz_pEXModulus F; build(F, f); do { random(r, deg(F)); if (IsOdd(zz_pE::cardinality())) { PowerMod(h, r, RightShift(zz_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_zz_pE& x, const zz_pEX& ff) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoots: bad args"); x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } void split(zz_pEX& f1, zz_pEX& g1, zz_pEX& f2, zz_pEX& g2, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots, long lo, long mid) { long r = mid-lo+1; zz_pEXModulus F; build(F, f); vec_zz_pE lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; zz_pEX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } void RecFindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } zz_pEX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } void FindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } void IterFindFactors(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& g, const vec_zz_pE& roots) { long r = roots.length(); long i; zz_pEX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b) { if (d < 0) LogicError("TraceMap: bad args"); zz_pEX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(zz_pEX& y, const zz_pEX& h, long q, const zz_pEXModulus& F) { if (q < 0) LogicError("PowerCompose: bad args"); zz_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const zz_pEX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX b, r, s; FrobeniusMap(b, F); long all_zero = 1; long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); all_zero = all_zero && IsZero(s); if (deg(s) > 0) return 0; } if (!all_zero || (n & 1)) return 1; PowerCompose(s, b, n/2, F); return !IsX(s); } NTL_CHEAP_THREAD_LOCAL long zz_pEX_BlockingFactor = 10; void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose) { vec_zz_pE roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } void EDFSplit(vec_zz_pEX& v, const zz_pEX& f, const zz_pEX& b, long d) { zz_pEX a, g, h; zz_pEXModulus F; vec_zz_pE roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } void RecEDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& b, long d, long verbose) { vec_zz_pEX v; long i; zz_pEX bb; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { zz_pEX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_zz_pEX& factors, const zz_pEX& ff, const zz_pEX& bb, long d, long verbose) { zz_pEX f = ff; zz_pEX b = bb; if (!IsOne(LeadCoeff(f))) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass(vec_zz_pEX& factors, const zz_pEX& ff, long verbose) { zz_pEX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; zz_pEXModulus F; build(F, f); zz_pEX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } FrobeniusMap(h, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_zz_pEX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } zz_pEX hh; vec_zz_pEX v; long i; for (i = 0; i < u.length(); i++) { const zz_pEX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("CanZass: bad args"); double t; vec_pair_zz_pEX_long sfd; vec_zz_pEX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); zz_pEX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } long BaseCase(const zz_pEX& h, long q, long a, const zz_pEXModulus& F) { long b, e; zz_pEX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(zz_pEX& y1, zz_pEX& y2, const zz_pEX& h, long q1, long q2, const zz_pEXModulus& F) { zz_pEX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const zz_pEX& h, const zz_pEXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); zz_pEX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } void FindRoot(zz_pE& root, const zz_pEX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { zz_pEXModulus F; zz_pEX h, h1, f; zz_pEX r; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r, deg(F)); if (IsOdd(zz_pE::cardinality())) { PowerMod(h, r, RightShift(zz_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const zz_pEX& h, long q, long a, const zz_pEXModulus& F) { long e; zz_pEX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const zz_pEX& h, const zz_pEXModulus& F, const FacVec& fvec) { long q1, q2; zz_pEX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const zz_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX h; FrobeniusMap(h, F); zz_pEX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const zz_pEX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pEXModulus F; build(F, f); zz_pEX h; FrobeniusMap(h, F); long CompTableSize = 2*SqrRoot(deg(f)); zz_pEXArgument H; build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; zz_pEX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { CompMod(g, g, H, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_zz_pEX& h, const zz_pEX& f, const zz_pEX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { zz_pEX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(zz_pEX& x, const zz_pEX& f, const zz_pEX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_zz_pEX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_zz_pE a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(zz_pEX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(zz_pEX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { zz_pEX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(zz_pEX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } #if 0 void BuildIrred(zz_pEX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (n == 1) { SetX(f); return; } zz_pEX g; do { random(g, n); SetCoeff(g, n); } while (!IterIrredTest(g)); f = g; } #endif void BuildRandomIrred(zz_pEX& f, const zz_pEX& g) { zz_pEXModulus G; zz_pEX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_CHEAP_THREAD_LOCAL long zz_pEX_GCDTableSize = 4; NTL_CHEAP_THREAD_LOCAL double zz_pEXFileThresh = NTL_FILE_THRESH; static NTL_CHEAP_THREAD_LOCAL vec_zz_pEX *BabyStepFile=0; static NTL_CHEAP_THREAD_LOCAL vec_zz_pEX *GiantStepFile=0; static NTL_CHEAP_THREAD_LOCAL long use_files; static double CalcTableSize(long n, long k) { double sz = zz_p::storage(); sz = sz*zz_pE::degree(); sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_p); sz = sz*n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_zz_pE); sz = sz * k; sz = sz/1024; return sz; } static void GenerateBabySteps(zz_pEX& h1, const zz_pEX& f, const zz_pEX& h, long k, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } zz_pEXModulus F; build(F, f); zz_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); h1 = h; long i; if (!use_files) { (*BabyStepFile).SetLength(k-1); } for (i = 1; i <= k-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("baby", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const zz_pEX& f, const zz_pEX& h, long l, FileList& flist, long verbose) { double t; if (verbose) { cerr << "generating giant steps..."; t = GetTime(); } zz_pEXModulus F; build(F, f); zz_pEXArgument H; #if 0 double n2 = sqrt(double(F.n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); zz_pEX h1; h1 = h; long i; if (!use_files) { (*GiantStepFile).SetLength(l); } for (i = 1; i <= l-1; i++) { if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "+"; } if (use_files) { ofstream s; OpenWrite(s, FileName("giant", i), flist); s << h1 << "\n"; CloseWrite(s); } else (*GiantStepFile)(i) = h1; if (verbose) cerr << (GetTime()-t) << "\n"; } static void NewAddFactor(vec_pair_zz_pEX_long& u, const zz_pEX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_zz_pEX_long& u, zz_pEX& f, const zz_pEXModulus& F, vec_zz_pEX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; zz_pEX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(zz_pEX& g, long gs, const zz_pEXModulus& F) { if (use_files) { ifstream s; OpenRead(s, FileName("giant", gs)); NTL_INPUT_CHECK_ERR(s >> g); } else g = (*GiantStepFile)(gs); rem(g, g, F); } static void FetchBabySteps(vec_zz_pEX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { if (use_files) { ifstream s; OpenRead(s, FileName("baby", i)); NTL_INPUT_CHECK_ERR(s >> v[i]); } else v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_zz_pEX_long& u, const zz_pEX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_zz_pEX BabyStep; FetchBabySteps(BabyStep, k); vec_zz_pEX buf(INIT_SIZE, zz_pEX_GCDTableSize); zz_pEX f; f = ff; zz_pEXModulus F; build(F, f); zz_pEX g; zz_pEX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == zz_pEX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_zz_pEX_long& factors, const zz_pEX& ff, long k, long gs, const vec_zz_pEX& BabyStep, long verbose) { vec_zz_pEX buf(INIT_SIZE, zz_pEX_GCDTableSize); zz_pEX f; f = ff; zz_pEXModulus F; build(F, f); zz_pEX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == zz_pEX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_zz_pEX_long& factors, const vec_pair_zz_pEX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_zz_pEX BabyStep; long i; for (i = 0; i < u.length(); i++) { const zz_pEX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); long l = (B+k-1)/k; zz_pEX h1; if (CalcTableSize(deg(f), k + l - 1) > zz_pEXFileThresh) use_files = 1; else use_files = 0; FileList flist; vec_zz_pEX local_BabyStepFile; vec_zz_pEX local_GiantStepFile; BabyStepFile = &local_BabyStepFile; GiantStepFile = &local_GiantStepFile; GenerateBabySteps(h1, f, h, k, flist, verbose); GenerateGiantSteps(f, h1, l, flist, verbose); vec_pair_zz_pEX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); } long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F) { long n = deg(F); if (n == 1 || IsX(h)) return 1; long B = n/2; long k = SqrRoot(B); long l = (B+k-1)/k; zz_pEXArgument H; #if 0 double n2 = sqrt(double(n)); double n4 = sqrt(n2); double n34 = n2*n4; long sz = long(ceil(n34/sqrt(sqrt(2.0)))); #else long sz = 2*SqrRoot(F.n); #endif build(H, h, F, sz); zz_pEX h1; h1 = h; vec_zz_pEX baby; baby.SetLength(k); SetX(baby[0]); long i; for (i = 1; i <= k-1; i++) { baby[i] = h1; CompMod(h1, h1, H, F); if (IsX(h1)) return i+1; } build(H, h1, F, sz); long j; for (j = 2; j <= l; j++) { CompMod(h1, h1, H, F); for (i = k-1; i >= 0; i--) { if (h1 == baby[i]) return j*k-i; } } return n; } NTL_END_IMPL ntl-11.5.1/src/lzz_pX.cpp0000644417616742025610000017515214064716022016751 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL // NOTE: these are declared extern in lzz_pX.h const long zz_pX_mod_crossover[5] = {45, 45, 90, 180, 180}; const long zz_pX_mul_crossover[5] = {150, 150, 300, 500, 500}; const long zz_pX_newton_crossover[5] = {150, 150, 300, 700, 700}; const long zz_pX_div_crossover[5] = {180, 180, 350, 750, 750}; const long zz_pX_halfgcd_crossover[5] = {90, 90, 180, 350, 350}; const long zz_pX_gcd_crossover[5] = {400, 400, 800, 1400, 1400}; const long zz_pX_bermass_crossover[5] = {400, 480, 900, 1600, 1600}; const long zz_pX_trace_crossover[5] = {200, 350, 450, 800, 800}; const zz_pX& zz_pX::zero() { static const zz_pX z; // GLOBAL (assumes C++11 thread-safe init) return z; } istream& operator>>(istream& s, zz_pX& x) { NTL_INPUT_CHECK_RET(s, s >> x.rep); x.normalize(); return s; } ostream& operator<<(ostream& s, const zz_pX& a) { return s << a.rep; } void zz_pX::normalize() { long n; const zz_p* p; n = rep.length(); if (n == 0) return; p = rep.elts() + n; while (n > 0 && IsZero(*--p)) { n--; } rep.SetLength(n); } long IsZero(const zz_pX& a) { return a.rep.length() == 0; } long IsOne(const zz_pX& a) { return a.rep.length() == 1 && IsOne(a.rep[0]); } void GetCoeff(zz_p& x, const zz_pX& a, long i) { if (i < 0 || i > deg(a)) clear(x); else x = a.rep[i]; } void SetCoeff(zz_pX& x, long i, zz_p a) { long j, m; if (i < 0) LogicError("SetCoeff: negative index"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m && IsZero(a)) return; if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } x.rep[i] = a; x.normalize(); } void SetCoeff(zz_pX& x, long i, long a) { if (a == 1) SetCoeff(x, i); else SetCoeff(x, i, to_zz_p(a)); } void SetCoeff(zz_pX& x, long i) { long j, m; if (i < 0) LogicError("coefficient index out of range"); if (NTL_OVERFLOW(i, 1, 0)) ResourceError("overflow in SetCoeff"); m = deg(x); if (i > m) { x.rep.SetLength(i+1); for (j = m+1; j < i; j++) clear(x.rep[j]); } set(x.rep[i]); x.normalize(); } void SetX(zz_pX& x) { clear(x); SetCoeff(x, 1); } long IsX(const zz_pX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); } const zz_p coeff(const zz_pX& a, long i) { if (i < 0 || i > deg(a)) return zz_p::zero(); else return a.rep[i]; } const zz_p LeadCoeff(const zz_pX& a) { if (IsZero(a)) return zz_p::zero(); else return a.rep[deg(a)]; } const zz_p ConstTerm(const zz_pX& a) { if (IsZero(a)) return zz_p::zero(); else return a.rep[0]; } void conv(zz_pX& x, zz_p a) { if (IsZero(a)) x.rep.SetLength(0); else { x.rep.SetLength(1); x.rep[0] = a; } } void conv(zz_pX& x, long a) { if (a == 0) { x.rep.SetLength(0); return; } zz_p t; conv(t, a); conv(x, t); } void conv(zz_pX& x, const ZZ& a) { if (a == 0) { x.rep.SetLength(0); return; } zz_p t; conv(t, a); conv(x, t); } void conv(zz_pX& x, const vec_zz_p& a) { x.rep = a; x.normalize(); } void add(zz_pX& x, const zz_pX& a, const zz_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_p *ap, *bp; zz_p* xp; long p = zz_p::modulus(); for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) xp->LoopHole() = AddMod(rep(*ap), rep(*bp), p); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab && &x != &b) for (i = db-minab; i; i--, xp++, bp++) *xp = *bp; else x.normalize(); } void add(zz_pX& x, const zz_pX& a, zz_p b) { if (a.rep.length() == 0) { conv(x, b); } else { if (&x != &a) x = a; add(x.rep[0], x.rep[0], b); x.normalize(); } } void sub(zz_pX& x, const zz_pX& a, const zz_pX& b) { long da = deg(a); long db = deg(b); long minab = min(da, db); long maxab = max(da, db); x.rep.SetLength(maxab+1); long i; const zz_p *ap, *bp; zz_p* xp; long p = zz_p::modulus(); for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts(); i; i--, ap++, bp++, xp++) xp->LoopHole() = SubMod(rep(*ap), rep(*bp), p); if (da > minab && &x != &a) for (i = da-minab; i; i--, xp++, ap++) *xp = *ap; else if (db > minab) for (i = db-minab; i; i--, xp++, bp++) xp->LoopHole() = NegateMod(rep(*bp), p); else x.normalize(); } void sub(zz_pX& x, const zz_pX& a, zz_p b) { if (a.rep.length() == 0) { x.rep.SetLength(1); negate(x.rep[0], b); } else { if (&x != &a) x = a; sub(x.rep[0], x.rep[0], b); } x.normalize(); } void sub(zz_pX& x, zz_p a, const zz_pX& b) { negate(x, b); add(x, x, a); } void negate(zz_pX& x, const zz_pX& a) { long n = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); long i; long p = zz_p::modulus(); for (i = n; i; i--, ap++, xp++) xp->LoopHole() = NegateMod(rep(*ap), p); } void mul(zz_pX& x, const zz_pX& a, const zz_pX& b) { if (&a == &b) { sqr(x, a); return; } if (deg(a) > NTL_zz_pX_MUL_CROSSOVER && deg(b) > NTL_zz_pX_MUL_CROSSOVER) FFTMul(x, a, b); else PlainMul(x, a, b); } void sqr(zz_pX& x, const zz_pX& a) { if (deg(a) > NTL_zz_pX_MUL_CROSSOVER) FFTSqr(x, a); else PlainSqr(x, a); } /* "plain" multiplication and squaring actually incorporates Karatsuba */ void PlainMul(zz_p *xp, const zz_p *ap, long sa, const zz_p *bp, long sb) { if (sa == 0 || sb == 0) return; long sx = sa+sb-1; if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = ap; ap = bp; bp = t; } } long i, j; for (i = 0; i < sx; i++) clear(xp[i]); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = 0; i < sb; i++) { long t1 = rep(bp[i]); mulmod_precon_t bpinv = PrepMulModPrecon(t1, p, pinv); zz_p *xp1 = xp+i; for (j = 0; j < sa; j++) { long t2; t2 = MulModPrecon(rep(ap[j]), t1, p, bpinv); xp1[j].LoopHole() = AddMod(t2, rep(xp1[j]), p); } } } static inline void reduce(zz_p& r, long a, long p, mulmod_t pinv) { // DIRT: uses undocumented MulMod feature (see sp_arith.h) r.LoopHole() = MulMod(a, 1L, p, pinv); } void PlainMul_long(zz_p *xp, const zz_p *ap, long sa, const zz_p *bp, long sb) { if (sa == 0 || sb == 0) return; long d = sa+sb-2; long i, j, jmin, jmax; long accum; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = 0; i <= d; i++) { jmin = max(0, i-(sb-1)); jmax = min((sa-1), i); accum = 0; for (j = jmin; j <= jmax; j++) { accum += rep(ap[j])*rep(bp[i-j]); } reduce(xp[i], accum, p, pinv); } } #define KARX (16) void KarFold(zz_p *T, const zz_p *b, long sb, long hsa) { long m = sb - hsa; long i; long p = zz_p::modulus(); for (i = 0; i < m; i++) T[i].LoopHole() = AddMod(rep(b[i]), rep(b[hsa+i]), p); for (i = m; i < hsa; i++) T[i] = b[i]; } void KarSub(zz_p *T, const zz_p *b, long sb) { long i; long p = zz_p::modulus(); for (i = 0; i < sb; i++) T[i].LoopHole() = SubMod(rep(T[i]), rep(b[i]), p); } void KarAdd(zz_p *T, const zz_p *b, long sb) { long i; long p = zz_p::modulus(); for (i = 0; i < sb; i++) T[i].LoopHole() = AddMod(rep(T[i]), rep(b[i]), p); } void KarFix(zz_p *c, const zz_p *b, long sb, long hsa) { long i; long p = zz_p::modulus(); for (i = 0; i < hsa; i++) c[i] = b[i]; for (i = hsa; i < sb; i++) c[i].LoopHole() = AddMod(rep(c[i]), rep(b[i]), p); } void KarMul(zz_p *c, const zz_p *a, long sa, const zz_p *b, long sb, zz_p *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = a; a = b; b = t; } } if (sb < KARX) { PlainMul(c, a, sa, b, sb); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; zz_p *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul(c, a, hsa, b, hsa, stk); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ zz_p *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void KarMul_long(zz_p *c, const zz_p *a, long sa, const zz_p *b, long sb, zz_p *stk) { if (sa < sb) { { long t = sa; sa = sb; sb = t; } { const zz_p *t = a; a = b; b = t; } } if (sb < KARX) { PlainMul_long(c, a, sa, b, sb); return; } long hsa = (sa + 1) >> 1; if (hsa < sb) { /* normal case */ long hsa2 = hsa << 1; zz_p *T1, *T2, *T3; T1 = stk; stk += hsa; T2 = stk; stk += hsa; T3 = stk; stk += hsa2 - 1; /* compute T1 = a_lo + a_hi */ KarFold(T1, a, sa, hsa); /* compute T2 = b_lo + b_hi */ KarFold(T2, b, sb, hsa); /* recursively compute T3 = T1 * T2 */ KarMul_long(T3, T1, hsa, T2, hsa, stk); /* recursively compute a_hi * b_hi into high part of c */ /* and subtract from T3 */ KarMul_long(c + hsa2, a+hsa, sa-hsa, b+hsa, sb-hsa, stk); KarSub(T3, c + hsa2, sa + sb - hsa2 - 1); /* recursively compute a_lo*b_lo into low part of c */ /* and subtract from T3 */ KarMul_long(c, a, hsa, b, hsa, stk); KarSub(T3, c, hsa2 - 1); clear(c[hsa2 - 1]); /* finally, add T3 * X^{hsa} to c */ KarAdd(c+hsa, T3, hsa2-1); } else { /* degenerate case */ zz_p *T; T = stk; stk += hsa + sb - 1; /* recursively compute b*a_hi into high part of c */ KarMul_long(c + hsa, a + hsa, sa - hsa, b, sb, stk); /* recursively compute b*a_lo into T */ KarMul_long(T, a, hsa, b, sb, stk); KarFix(c, T, hsa + sb - 1, hsa); } } void PlainMul(zz_pX& c, const zz_pX& a, const zz_pX& b) { long sa = a.rep.length(); long sb = b.rep.length(); if (sa == 0 || sb == 0) { clear(c); return; } if (sa == 1) { mul(c, b, a.rep[0]); return; } if (sb == 1) { mul(c, a, b.rep[0]); return; } if (&a == &b) { PlainSqr(c, a); return; } vec_zz_p mem; const zz_p *ap, *bp; zz_p *cp; if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); if (&b == &c) { mem = b.rep; bp = mem.elts(); } else bp = b.rep.elts(); c.rep.SetLength(sa+sb-1); cp = c.rep.elts(); long p = zz_p::modulus(); long use_long = (p < NTL_SP_BOUND/KARX && p*KARX < NTL_SP_BOUND/p); if (sa < KARX || sb < KARX) { if (use_long) PlainMul_long(cp, ap, sa, bp, sb); else PlainMul(cp, ap, sa, bp, sb); } else { /* karatsuba */ long n, hn, sp; n = max(sa, sb); sp = 0; do { hn = (n+1) >> 1; sp += (hn << 2) - 1; n = hn; } while (n >= KARX); vec_zz_p stk; stk.SetLength(sp); if (use_long) KarMul_long(cp, ap, sa, bp, sb, stk.elts()); else KarMul(cp, ap, sa, bp, sb, stk.elts()); } c.normalize(); } void PlainSqr_long(zz_p *xp, const zz_p *ap, long sa) { if (sa == 0) return; long da = sa-1; long d = 2*da; long i, j, jmin, jmax, m, m2; long accum; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = 0; i <= d; i++) { jmin = max(0, i-da); jmax = min(da, i); m = jmax - jmin + 1; m2 = m >> 1; jmax = jmin + m2 - 1; accum = 0; for (j = jmin; j <= jmax; j++) { accum += rep(ap[j])*rep(ap[i-j]); } accum += accum; if (m & 1) { accum += rep(ap[jmax + 1])*rep(ap[jmax + 1]); } reduce(xp[i], accum, p, pinv); } } void PlainSqr(zz_p *xp, const zz_p *ap, long sa) { if (sa == 0) return; long i, j, k, cnt; cnt = 2*sa-1; for (i = 0; i < cnt; i++) clear(xp[i]); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long t1, t2; i = -1; for (j = 0; j <= sa-2; j++) { i += 2; t1 = MulMod(rep(ap[j]), rep(ap[j]), p, pinv); t2 = rep(xp[i-1]); t2 = AddMod(t2, t2, p); t2 = AddMod(t2, t1, p); xp[i-1].LoopHole() = t2; cnt = sa - 1 - j; const zz_p *ap1 = ap+(j+1); zz_p *xp1 = xp+i; t1 = rep(ap[j]); mulmod_precon_t tpinv = PrepMulModPrecon(t1, p, pinv); for (k = 0; k < cnt; k++) { t2 = MulModPrecon(rep(ap1[k]), t1, p, tpinv); t2 = AddMod(t2, rep(xp1[k]), p); xp1[k].LoopHole() = t2; } t2 = rep(*xp1); t2 = AddMod(t2, t2, p); (*xp1).LoopHole() = t2; } t1 = rep(ap[sa-1]); t1 = MulMod(t1, t1, p, pinv); xp[2*sa-2].LoopHole() = t1; } #define KARSX (30) void KarSqr(zz_p *c, const zz_p *a, long sa, zz_p *stk) { if (sa < KARSX) { PlainSqr(c, a, sa); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; zz_p *T1, *T2; T1 = stk; stk += hsa; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr(T2, T1, hsa, stk); KarSqr(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void KarSqr_long(zz_p *c, const zz_p *a, long sa, zz_p *stk) { if (sa < KARSX) { PlainSqr_long(c, a, sa); return; } long hsa = (sa + 1) >> 1; long hsa2 = hsa << 1; zz_p *T1, *T2; T1 = stk; stk += hsa; T2 = stk; stk += hsa2-1; KarFold(T1, a, sa, hsa); KarSqr_long(T2, T1, hsa, stk); KarSqr_long(c + hsa2, a+hsa, sa-hsa, stk); KarSub(T2, c + hsa2, sa + sa - hsa2 - 1); KarSqr_long(c, a, hsa, stk); KarSub(T2, c, hsa2 - 1); clear(c[hsa2 - 1]); KarAdd(c+hsa, T2, hsa2-1); } void PlainSqr(zz_pX& c, const zz_pX& a) { if (IsZero(a)) { clear(c); return; } vec_zz_p mem; const zz_p *ap; zz_p *cp; long sa = a.rep.length(); if (&a == &c) { mem = a.rep; ap = mem.elts(); } else ap = a.rep.elts(); c.rep.SetLength(2*sa-1); cp = c.rep.elts(); long p = zz_p::modulus(); long use_long = (p < NTL_SP_BOUND/KARSX && p*KARSX < NTL_SP_BOUND/p); if (sa < KARSX) { if (use_long) PlainSqr_long(cp, ap, sa); else PlainSqr(cp, ap, sa); } else { /* karatsuba */ long n, hn, sp; n = sa; sp = 0; do { hn = (n+1) >> 1; sp += hn+hn+hn - 1; n = hn; } while (n >= KARSX); vec_zz_p stk; stk.SetLength(sp); if (use_long) KarSqr_long(cp, ap, sa, stk.elts()); else KarSqr(cp, ap, sa, stk.elts()); } c.normalize(); } void PlainDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *qp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pX: division by zero"); if (da < db) { r = a; clear(q); return; } zz_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; if (&r == &a) xp = r.rep.elts(); else { x = a.rep; xp = x.elts(); } dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i+db]; if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); for (j = db-1; j >= 0; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j]), p); xp[i+j].LoopHole() = S; } } r.rep.SetLength(db); if (&r != &a) { for (i = 0; i < db; i++) r.rep[i] = xp[i]; } r.normalize(); } void PlainDiv(zz_pX& q, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *qp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pX: division by zero"); if (da < db) { clear(q); return; } zz_pX lb; if (&q == &b) { lb = b; bp = lb.rep.elts(); } else bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; x.SetLength(da+1-db); for (i = db; i <= da; i++) x[i-db] = a.rep[i]; xp = x.elts(); dq = da - db; q.rep.SetLength(dq+1); qp = q.rep.elts(); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i]; if (!LCIsOne) mul(t, t, LCInv); qp[i] = t; negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); long lastj = max(0, db-i); for (j = db-1; j >= lastj; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j-db]), p); xp[i+j-db].LoopHole() = S; } } } void PlainRem(zz_pX& r, const zz_pX& a, const zz_pX& b) { long da, db, dq, i, j, LCIsOne; const zz_p *bp; zz_p *xp; zz_p LCInv, t; zz_p s; da = deg(a); db = deg(b); if (db < 0) ArithmeticError("zz_pX: division by zero"); if (da < db) { r = a; return; } bp = b.rep.elts(); if (IsOne(bp[db])) LCIsOne = 1; else { LCIsOne = 0; inv(LCInv, bp[db]); } vec_zz_p x; if (&r == &a) xp = r.rep.elts(); else { x = a.rep; xp = x.elts(); } dq = da - db; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); for (i = dq; i >= 0; i--) { t = xp[i+db]; if (!LCIsOne) mul(t, t, LCInv); negate(t, t); long T = rep(t); mulmod_precon_t Tpinv = PrepMulModPrecon(T, p, pinv); for (j = db-1; j >= 0; j--) { long S = MulModPrecon(rep(bp[j]), T, p, Tpinv); S = AddMod(S, rep(xp[i+j]), p); xp[i+j].LoopHole() = S; } } r.rep.SetLength(db); if (&r != &a) { for (i = 0; i < db; i++) r.rep[i] = xp[i]; } r.normalize(); } void mul(zz_pX& x, const zz_pX& a, zz_p b) { if (IsZero(b)) { clear(x); return; } if (IsOne(b)) { x = a; return; } long i, da; const zz_p *ap; zz_p* xp; long t; t = rep(b); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); mulmod_precon_t bpinv = PrepMulModPrecon(t, p, pinv); da = deg(a); x.rep.SetLength(da+1); ap = a.rep.elts(); xp = x.rep.elts(); for (i = 0; i <= da; i++) xp[i].LoopHole() = MulModPrecon(rep(ap[i]), t, p, bpinv); x.normalize(); } void PlainGCD(zz_pX& x, const zz_pX& a, const zz_pX& b) { zz_p t; if (IsZero(b)) x = a; else if (IsZero(a)) x = b; else { long n = max(deg(a),deg(b)) + 1; zz_pX u(INIT_SIZE, n), v(INIT_SIZE, n); u = a; v = b; do { PlainRem(u, u, v); swap(u, v); } while (!IsZero(v)); x = u; } if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; /* make gcd monic */ inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainXGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b) { zz_p z; if (IsZero(b)) { set(s); clear(t); d = a; } else if (IsZero(a)) { clear(s); set(t); d = b; } else { long e = max(deg(a), deg(b)) + 1; zz_pX temp(INIT_SIZE, e), u(INIT_SIZE, e), v(INIT_SIZE, e), u0(INIT_SIZE, e), v0(INIT_SIZE, e), u1(INIT_SIZE, e), v1(INIT_SIZE, e), u2(INIT_SIZE, e), v2(INIT_SIZE, e), q(INIT_SIZE, e); set(u1); clear(v1); clear(u2); set(v2); u = a; v = b; do { DivRem(q, u, u, v); swap(u, v); u0 = u2; v0 = v2; mul(temp, q, u2); sub(u2, u1, temp); mul(temp, q, v2); sub(v2, v1, temp); u1 = u0; v1 = v0; } while (!IsZero(v)); d = u; s = u1; t = v1; } if (IsZero(d)) return; if (IsOne(LeadCoeff(d))) return; /* make gcd monic */ inv(z, LeadCoeff(d)); mul(d, d, z); mul(s, s, z); mul(t, t, z); } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f) { if (deg(a) >= deg(f) || deg(b) >= deg(f) || deg(f) == 0) LogicError("MulMod: bad args"); zz_pX t; mul(t, a, b); rem(x, t, f); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("SqrMod: bad args"); zz_pX t; sqr(t, a); rem(x, t, f); } void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvMod: bad args"); zz_pX d, xx, t; XGCD(d, xx, t, a, f); if (!IsOne(d)) InvModError("zz_pX InvMod: can't compute multiplicative inverse"); x = xx; } long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) == 0) LogicError("InvModStatus: bad args"); zz_pX d, t; XGCD(d, x, t, a, f); if (!IsOne(d)) { x = d; return 1; } else return 0; } static void MulByXModAux(zz_pX& h, const zz_pX& a, const zz_pX& f) { long i, n, m; zz_p* hh; const zz_p *aa, *ff; zz_p t, z; n = deg(f); m = deg(a); if (m >= n || n == 0) LogicError("MulByXMod: bad args"); if (m < 0) { clear(h); return; } if (m < n-1) { h.rep.SetLength(m+2); hh = h.rep.elts(); aa = a.rep.elts(); for (i = m+1; i >= 1; i--) hh[i] = aa[i-1]; clear(hh[0]); } else { h.rep.SetLength(n); hh = h.rep.elts(); aa = a.rep.elts(); ff = f.rep.elts(); negate(z, aa[n-1]); if (!IsOne(ff[n])) div(z, z, ff[n]); for (i = n-1; i >= 1; i--) { mul(t, z, ff[i]); add(hh[i], aa[i-1], t); } mul(hh[0], z, ff[0]); h.normalize(); } } void MulByXMod(zz_pX& h, const zz_pX& a, const zz_pX& f) { if (&h == &f) { zz_pX hh; MulByXModAux(hh, a, f); h = hh; } else MulByXModAux(h, a, f); } void random(zz_pX& x, long n) { x.rep.SetLength(n); VectorRandom(n, x.rep.elts()); x.normalize(); } void fftRep::DoSetSize(long NewK, long NewNumPrimes) { if (NewK < -1) LogicError("bad arg to fftRep::SetSize()"); if (NewK >= NTL_BITS_PER_LONG-1) ResourceError("bad arg to fftRep::SetSize()"); if (NewK == -1) { k = -1; return; } if (NewNumPrimes == 0) NewNumPrimes = zz_pInfo->NumPrimes; if (MaxK >= 0 && NumPrimes != NewNumPrimes) LogicError("fftRep: inconsistent use"); if (NewK <= MaxK) { k = NewK; return; } UniqueArray new_tbl[4]; long i; for (i = 0; i < NewNumPrimes; i++) new_tbl[i].SetLength(1L << NewK); for (i = 0; i < NewNumPrimes; i++) tbl[i].move(new_tbl[i]); NumPrimes = NewNumPrimes; k = MaxK = NewK; } void fftRep::SetSize(long NewK) { DoSetSize(NewK, 0); } fftRep& fftRep::operator=(const fftRep& R) { if (this == &R) return *this; if (MaxK >= 0 && R.MaxK >= 0 && NumPrimes != R.NumPrimes) LogicError("fftRep: inconsistent use"); if (R.k < 0) { k = -1; len = 0; return *this; } DoSetSize(R.k, R.NumPrimes); len = R.len; long i, j; for (i = 0; i < NumPrimes; i++) for (j = 0; j < len; j++) tbl[i][j] = R.tbl[i][j]; return *this; } static inline void FromModularRep(zz_p& res, long *a, zz_pInfoT* info) { long n = info->NumPrimes; long p = info->p; mulmod_t pinv = info->pinv; long *CoeffModP = info->CoeffModP.elts(); double *x = info->x.elts(); long *u = info->u.elts(); mulmod_precon_t *uqinv = info->uqinv.elts(); long MinusMModP = info->MinusMModP; mulmod_precon_t MinusMModPpinv = info->MinusMModPpinv; mulmod_precon_t *CoeffModPpinv = info->CoeffModPpinv.elts(); long q, s, t; long i; double y; y = double(0L); t = 0; for (i = 0; i < n; i++) { s = MulModPrecon(a[i], u[i], GetFFTPrime(i), uqinv[i]); y = y + double(s)*GetFFTPrimeRecip(i); // DIRT: uses undocumented MulMod feature (see sp_arith.h) // input s is not reduced mod p s = MulModPrecon(s, CoeffModP[i], p, CoeffModPpinv[i]); t = AddMod(t, s, p); } q = (long) (y + 0.5); // DIRT: uses undocumented MulMod feature (see sp_arith.h) // input q may not be reduced mod p s = MulModPrecon(q, MinusMModP, p, MinusMModPpinv); t = AddMod(t, s, p); res.LoopHole() = t; } #if 0 // converts entries lo..lo+cnt-1 in R and stores results into res static void FromModularRep(zz_p* res, const fftRep& R, long lo, long cnt, zz_pInfoT* info) { if (cnt <= 0) return; long nprimes = info->NumPrimes; long p = info->p; mulmod_t pinv = info->pinv; long *CoeffModP = info->CoeffModP.elts(); double *x = info->x.elts(); long *u = info->u.elts(); mulmod_precon_t *uqinv = info->uqinv.elts(); long MinusMModP = info->MinusMModP; mulmod_precon_t MinusMModPpinv = info->MinusMModPpinv; mulmod_precon_t *CoeffModPpinv = info->CoeffModPpinv.elts(); long primes[4]; double prime_recip[4]; long *tbl[4]; long q, s, t; long i, j; double y; for (i = 0; i < nprimes; i++) { primes[i] = GetFFTPrime(i); prime_recip[i] = GetFFTPrimeRecip(i); tbl[i] = R.tbl[i].get(); } for (j = 0; j < cnt; j++) { y = double(0L); t = 0; for (i = 0; i < nprimes; i++) { s = MulModPrecon(tbl[i][j+lo], u[i], primes[i], uqinv[i]); y = y + double(s)*prime_recip[i]; // DIRT: uses undocumented MulMod feature (see sp_arith.h) // input s is not reduced mod p s = MulModPrecon(s, CoeffModP[i], p, CoeffModPpinv[i]); t = AddMod(t, s, p); } q = (long) (y + 0.5); // DIRT: uses undocumented MulMod feature (see sp_arith.h) // input q may not be reduced mod p s = MulModPrecon(q, MinusMModP, p, MinusMModPpinv); t = AddMod(t, s, p); res[j].LoopHole() = t; } } #else #define NTL_FMR_LOOP_BODY(i) \ s = MulModPrecon(tbl[i][j+lo], u[i], primes[i], uqinv[i]);\ y = y + double(s)*prime_recip[i];\ \ \ /* DIRT: uses undocumented MulMod feature (see sp_arith.h) */\ /* input s is not reduced mod p */\ s = MulModPrecon(s, CoeffModP[i], p, CoeffModPpinv[i]);\ \ t = AddMod(t, s, p);\ #define NTL_FMP_OUTER_LOOP(XXX) \ for (j = 0; j < cnt; j++) {\ y = double(0L);\ t = 0;\ XXX \ q = (long) (y + 0.5);\ /* DIRT: uses undocumented MulMod feature (see sp_arith.h) */\ /* input q may not be reduced mod p */\ s = MulModPrecon(q, MinusMModP, p, MinusMModPpinv);\ t = AddMod(t, s, p);\ res[j].LoopHole() = t;\ }\ // converts entries lo..lo+cnt-1 in R and stores results into res static void FromModularRep(zz_p* res, const fftRep& R, long lo, long cnt, zz_pInfoT* info) { if (cnt <= 0) return; long nprimes = info->NumPrimes; long p = info->p; mulmod_t pinv = info->pinv; long *CoeffModP = info->CoeffModP.elts(); double *x = info->x.elts(); long *u = info->u.elts(); mulmod_precon_t *uqinv = info->uqinv.elts(); long MinusMModP = info->MinusMModP; mulmod_precon_t MinusMModPpinv = info->MinusMModPpinv; mulmod_precon_t *CoeffModPpinv = info->CoeffModPpinv.elts(); long primes[4]; double prime_recip[4]; long *tbl[4]; long q, s, t; long i, j; double y; for (i = 0; i < nprimes; i++) { primes[i] = GetFFTPrime(i); prime_recip[i] = GetFFTPrimeRecip(i); tbl[i] = R.tbl[i].get(); } if (nprimes == 1) { long *tbl_0 = tbl[0]; mulmod_precon_t CoeffModPpinv_0 = CoeffModPpinv[0]; long primes_0 = primes[0]; long hp0 = primes_0 >> 1; for (j = 0; j < cnt; j++) { s = tbl_0[j+lo]; // DIRT: uses undocumented MulMod feature (see sp_arith.h) // input s is not reduced mod p t = MulModPrecon(s, 1, p, CoeffModPpinv_0); res[j].LoopHole() = AddMod(t, sp_SignMask(hp0-s) & MinusMModP, p); } } else if (nprimes == 2) { NTL_FMP_OUTER_LOOP( NTL_FMR_LOOP_BODY(0) NTL_FMR_LOOP_BODY(1) ) } else if (nprimes == 3) { NTL_FMP_OUTER_LOOP( NTL_FMR_LOOP_BODY(0) NTL_FMR_LOOP_BODY(1) NTL_FMR_LOOP_BODY(2) ) } else { // nprimes == 4 NTL_FMP_OUTER_LOOP( NTL_FMR_LOOP_BODY(0) NTL_FMR_LOOP_BODY(1) NTL_FMR_LOOP_BODY(2) NTL_FMR_LOOP_BODY(3) ) } } #endif void TofftRep_trunc(fftRep& y, const zz_pX& x, long k, long len, long lo, long hi) // computes an n = 2^k point convolution. // if deg(x) >= 2^k, then x is first reduced modulo X^n-1. { zz_pInfoT *info = zz_pInfo; long p = info->p; long n, i, j, m, j1; long accum; long nprimes = info->NumPrimes; if (k > info->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to TofftRep"); hi = min(hi, deg(x)); y.SetSize(k); n = 1L << k; y.len = len = FFTRoundUp(len, k); m = max(hi-lo + 1, 0); long ilen = FFTRoundUp(m, k); const zz_p *xx = x.rep.elts(); FFTPrimeInfo *p_info = info->p_info; if (p_info) { if (n >= m) { long *yp = &y.tbl[0][0]; for (j = 0; j < m; j++) { yp[j] = rep(xx[j+lo]); } for (j = m; j < ilen; j++) { yp[j] = 0; } } else { for (j = 0; j < n; j++) { accum = rep(xx[j+lo]); for (j1 = j + n; j1 < m; j1 += n) accum = AddMod(accum, rep(xx[j1+lo]), p); y.tbl[0][j] = accum; } } } else { if (n >= m) { for (i = 0; i < nprimes; i++) { long q = GetFFTPrime(i); long *yp = &y.tbl[i][0]; for (j = 0; j < m; j++) { long t = rep(xx[j+lo]); t = sp_CorrectExcess(t, q); yp[j] = t; } for (j = m; j < ilen; j++) { yp[j] = 0; } } } else { for (j = 0; j < n; j++) { accum = rep(xx[j+lo]); for (j1 = j + n; j1 < m; j1 += n) accum = AddMod(accum, rep(xx[j1+lo]), p); for (i = 0; i < nprimes; i++) { long q = GetFFTPrime(i); long t = accum; t = sp_CorrectExcess(t, q); y.tbl[i][j] = t; } } } } if (p_info) { long *yp = &y.tbl[0][0]; FFTFwd_trunc(yp, yp, k, *p_info, len, ilen); } else { for (i = 0; i < nprimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd_trunc(yp, yp, k, i, len, ilen); } } } void RevTofftRep(fftRep& y, const vec_zz_p& x, long k, long lo, long hi, long offset) // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. { zz_pInfoT *info = zz_pInfo; long p = info->p; long n, i, j, m, j1; long accum; long NumPrimes = info->NumPrimes; if (k > info->MaxRoot) ResourceError("Polynomial too big for FFT"); if (lo < 0) LogicError("bad arg to TofftRep"); hi = min(hi, x.length()-1); y.SetSize(k); n = 1L << k; y.len = n; m = max(hi-lo + 1, 0); const zz_p *xx = x.elts(); FFTPrimeInfo *p_info = info->p_info; offset = offset & (n-1); if (p_info) { for (j = 0; j < n; j++) { if (j >= m) { y.tbl[0][offset] = 0; } else { accum = rep(xx[j+lo]); for (j1 = j + n; j1 < m; j1 += n) accum = AddMod(accum, rep(xx[j1+lo]), p); y.tbl[0][offset] = accum; } offset = (offset + 1) & (n-1); } } else { for (j = 0; j < n; j++) { if (j >= m) { for (i = 0; i < NumPrimes; i++) y.tbl[i][offset] = 0; } else { accum = rep(xx[j+lo]); for (j1 = j + n; j1 < m; j1 += n) accum = AddMod(accum, rep(xx[j1+lo]), p); for (i = 0; i < NumPrimes; i++) { long q = GetFFTPrime(i); long t = accum; t = sp_CorrectExcess(t, q); y.tbl[i][offset] = t; } } offset = (offset + 1) & (n-1); } } if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1_trans(yp, yp, k, *p_info); } else { for (i = 0; i < info->NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trans(yp, yp, k, i); } } } void FromfftRep(zz_pX& x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { zz_pInfoT *info = zz_pInfo; long k, n, i, j, l; long NumPrimes = info->NumPrimes; k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromfftRep: bad len"); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1_trunc(yp, yp, k, *p_info, len); } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1_trunc(yp, yp, k, i, len); } } x.rep.SetLength(l); if (p_info) { zz_p *xp = x.rep.elts(); long *yp = &y.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = yp[j+lo]; } else { FromModularRep(x.rep.elts(), y, lo, l, info); } x.normalize(); } void RevFromfftRep(vec_zz_p& x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed { zz_pInfoT *info = zz_pInfo; long k, n, i, j, l; long NumPrimes = info->NumPrimes; k = y.k; n = (1L << k); if (y.len != n) LogicError("RevFromfftRep: bad len"); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTFwd_trans(yp, yp, k, *p_info); } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTFwd_trans(yp, yp, k, i); } } hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); x.SetLength(l); if (p_info) { zz_p *xp = x.elts(); long *yp = &y.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = yp[j+lo]; } else { FromModularRep(x.elts(), y, lo, l, info); } } void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi, fftRep& z) { zz_pInfoT *info = zz_pInfo; long k, n, i, j, l; long NumPrimes = info->NumPrimes; k = y.k; n = (1L << k); hi = min(hi, n-1); l = hi-lo+1; l = max(l, 0); long len = y.len; if (len <= hi) LogicError("FromfftRep: bad len"); z.SetSize(k); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *yp = &y.tbl[0][0]; FFTRev1_trunc(zp, yp, k, *p_info, len); } else { for (i = 0; i < NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *yp = &y.tbl[i][0]; FFTRev1_trunc(zp, yp, k, i, len); } } x.rep.SetLength(l); if (p_info) { zz_p *xp = x.rep.elts(); long *zp = &z.tbl[0][0]; for (j = 0; j < l; j++) xp[j].LoopHole() = zp[j+lo]; } else { FromModularRep(x.rep.elts(), z, lo, l, info); } x.normalize(); } void NDFromfftRep(zz_pX& x, fftRep& y, long lo, long hi) { fftRep z; NDFromfftRep(x, y, lo, hi, z); } void FromfftRep(zz_p* x, fftRep& y, long lo, long hi) // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed { zz_pInfoT *info = zz_pInfo; long k, n, i, j; long NumPrimes = info->NumPrimes; k = y.k; n = (1L << k); //if (y.len <= min(hi, n-1)) LogicError("FromfftRep: bad len"); if (y.len != n) LogicError("FromfftRep: bad len"); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *yp = &y.tbl[0][0]; FFTRev1(yp, yp, k, *p_info); for (j = lo; j <= hi; j++) { if (j >= n) clear(x[j-lo]); else { x[j-lo].LoopHole() = y.tbl[0][j]; } } } else { for (i = 0; i < NumPrimes; i++) { long *yp = &y.tbl[i][0]; FFTRev1(yp, yp, k, i); } // take coefficients lo..min(hi, n-1) from y // zero out coefficients max(n, lo)..hi long l = min(hi, n-1) - lo + 1; l = max(l, 0); FromModularRep(x, y, lo, l, info); for (j = max(n, lo); j <= hi; j++) clear(x[j-lo]); } } void mul(fftRep& z, const fftRep& x, const fftRep& y) { zz_pInfoT *info = zz_pInfo; long k, n, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); long len = z.len = min(x.len, y.len); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; mulmod_t qinv = p_info->qinv; if (NormalizedModulus(qinv)) { for (j = 0; j < len; j++) zp[j] = NormalizedMulMod(xp[j], yp[j], q, qinv); } else { for (j = 0; j < len; j++) zp[j] = MulMod(xp[j], yp[j], q, qinv); } } else { for (i = 0; i < info->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); mulmod_t qinv = GetFFTPrimeInv(i); for (j = 0; j < len; j++) zp[j] = NormalizedMulMod(xp[j], yp[j], q, qinv); } } } void sub(fftRep& z, const fftRep& x, const fftRep& y) { zz_pInfoT *info = zz_pInfo; long k, n, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); long len = z.len = min(x.len, y.len); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; for (j = 0; j < len; j++) zp[j] = SubMod(xp[j], yp[j], q); } else { for (i = 0; i < info->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (j = 0; j < len; j++) zp[j] = SubMod(xp[j], yp[j], q); } } } void add(fftRep& z, const fftRep& x, const fftRep& y) { zz_pInfoT *info = zz_pInfo; long k, n, i, j; if (x.k != y.k) LogicError("FFT rep mismatch"); k = x.k; n = 1L << k; z.SetSize(k); long len = z.len = min(x.len, y.len); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long *zp = &z.tbl[0][0]; const long *xp = &x.tbl[0][0]; const long *yp = &y.tbl[0][0]; long q = p_info->q; for (j = 0; j < len; j++) zp[j] = AddMod(xp[j], yp[j], q); } else { for (i = 0; i < info->NumPrimes; i++) { long *zp = &z.tbl[i][0]; const long *xp = &x.tbl[i][0]; const long *yp = &y.tbl[i][0]; long q = GetFFTPrime(i); for (j = 0; j < len; j++) zp[j] = AddMod(xp[j], yp[j], q); } } } void reduce(fftRep& x, const fftRep& a, long k) // reduces a 2^l point FFT-rep to a 2^k point FFT-rep // input may alias output { zz_pInfoT *info = zz_pInfo; long i, j, l, n; long* xp; const long* ap; l = a.k; n = 1L << k; if (l < k) LogicError("reduce: bad operands"); if (a.len < n) LogicError("reduce: bad len"); x.SetSize(k); x.len = n; if (&x == &a) return; for (i = 0; i < info->NumPrimes; i++) { ap = &a.tbl[i][0]; xp = &x.tbl[i][0]; for (j = 0; j < n; j++) xp[j] = ap[j]; } } void AddExpand(fftRep& x, const fftRep& a) // x = x + (an "expanded" version of a) { zz_pInfoT *info = zz_pInfo; long i, j, l, k, n; l = x.k; k = a.k; n = 1L << k; if (l < k) LogicError("AddExpand: bad args"); if (x.len < n) LogicError("AddExpand: bad len"); FFTPrimeInfo *p_info = info->p_info; if (p_info) { long q = p_info->q; const long *ap = &a.tbl[0][0]; long *xp = &x.tbl[0][0]; for (j = 0; j < n; j++) { xp[j] = AddMod(xp[j], ap[j], q); } } else { for (i = 0; i < info->NumPrimes; i++) { long q = GetFFTPrime(i); const long *ap = &a.tbl[i][0]; long *xp = &x.tbl[i][0]; for (j = 0; j < n; j++) { xp[j] = AddMod(xp[j], ap[j], q); } } } } void FFTMul(zz_pX& x, const zz_pX& a, const zz_pX& b) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long da = deg(a); long db = deg(b); long d = da+db; long k = NextPowerOfTwo(d+1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep_trunc(R1, a, k, d+1); TofftRep_trunc(R2, b, k, d+1); mul(R1, R1, R2); FromfftRep(x, R1, 0, d); } void FFTSqr(zz_pX& x, const zz_pX& a) { if (IsZero(a)) { clear(x); return; } long da = deg(a); long d = 2*da; long k = NextPowerOfTwo(d+1); fftRep R1(INIT_SIZE, k); TofftRep_trunc(R1, a, k, d+1); mul(R1, R1, R1); FromfftRep(x, R1, 0, d); } void CopyReverse(zz_pX& x, const zz_pX& a, long lo, long hi) // x[0..hi-lo] = reverse(a[lo..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void copy(zz_pX& x, const zz_pX& a, long lo, long hi) // x[0..hi-lo] = a[lo..hi], with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = lo + i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); } void rem21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { x = a; return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainRem(x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-2, 2*n-4); TofftRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromfftRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const zz_p* aa = a.rep.elts(); const zz_p* ss = P1.rep.elts(); zz_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); } void DivRem21(zz_pX& q, zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long i, da, ds, n, kk; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { x = a; clear(q); return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDivRem(q, x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n), qq; TofftRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-2, 2*n-4); qq = P1; TofftRep(R1, P1, F.k); mul(R1, R1, F.FRep); FromfftRep(P1, R1, 0, n-1); ds = deg(P1); kk = 1L << F.k; x.rep.SetLength(n); const zz_p* aa = a.rep.elts(); const zz_p* ss = P1.rep.elts(); zz_p* xx = x.rep.elts(); for (i = 0; i < n; i++) { if (i <= ds) sub(xx[i], aa[i], ss[i]); else xx[i] = aa[i]; if (i + kk <= da) add(xx[i], xx[i], aa[i+kk]); } x.normalize(); q = qq; } void div21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da, n; da = deg(a); n = F.n; if (da > 2*n-2) LogicError("bad args to rem(zz_pX,zz_pX,zz_pXModulus)"); if (da < n) { clear(x); return; } if (!F.UseFFT || da - n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDiv(x, a, F.f); return; } fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep_trunc(R1, a, F.l, 2*n-3, n, 2*(n-1)); mul(R1, R1, F.HRep); FromfftRep(x, R1, n-2, 2*n-4); } void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("rem: uninitialized modulus"); if (da <= 2*n-2) { rem21(x, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainRem(x, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); long a_len = da+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); rem21(buf, buf, F); a_len -= amt; } x = buf; } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("DivRem: uninitialized modulus"); if (da <= 2*n-2) { DivRem21(q, r, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDivRem(q, r, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); zz_pX qbuf(INIT_SIZE, n-1); zz_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); DivRem21(qbuf, buf, buf, F); long dl = qbuf.rep.length(); a_len = a_len - amt; for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } r = buf; qq.normalize(); q = qq; } void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F) { long da = deg(a); long n = F.n; if (n < 0) LogicError("div: uninitialized modulus"); if (da <= 2*n-2) { div21(q, a, F); return; } else if (!F.UseFFT || da-n <= NTL_zz_pX_MOD_CROSSOVER) { PlainDiv(q, a, F.f); return; } zz_pX buf(INIT_SIZE, 2*n-1); zz_pX qbuf(INIT_SIZE, n-1); zz_pX qq; qq.rep.SetLength(da-n+1); long a_len = da+1; long q_hi = da-n+1; while (a_len > 0) { long old_buf_len = buf.rep.length(); long amt = min(2*n-1-old_buf_len, a_len); buf.rep.SetLength(old_buf_len+amt); long i; for (i = old_buf_len+amt-1; i >= amt; i--) buf.rep[i] = buf.rep[i-amt]; for (i = amt-1; i >= 0; i--) buf.rep[i] = a.rep[a_len-amt+i]; buf.normalize(); a_len = a_len - amt; if (a_len > 0) DivRem21(qbuf, buf, buf, F); else div21(qbuf, buf, F); long dl = qbuf.rep.length(); for(i = 0; i < dl; i++) qq.rep[a_len+i] = qbuf.rep[i]; for(i = dl+a_len; i < q_hi; i++) clear(qq.rep[i]); q_hi = a_len; } qq.normalize(); q = qq; } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F) { long da, db, d, n, k; da = deg(a); db = deg(b); n = F.n; if (n < 0) LogicError("MulMod: uninitialized modulus"); if (da >= n || db >= n) LogicError("bad args to MulMod(zz_pX,zz_pX,zz_pX,zz_pXModulus)"); if (da < 0 || db < 0) { clear(x); return; } if (!F.UseFFT || da <= NTL_zz_pX_MUL_CROSSOVER || db <= NTL_zz_pX_MUL_CROSSOVER) { zz_pX P1; mul(P1, a, b); rem(x, P1, F); return; } d = da + db + 1; k = NextPowerOfTwo(d); k = max(k, F.k); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); long len; if (zz_p::IsFFTPrime()) len = n; else len = 1L << F.k; TofftRep_trunc(R1, a, k, max(1L << F.k, d)); TofftRep_trunc(R2, b, k, max(1L << F.k, d)); mul(R1, R1, R2); NDFromfftRep(P1, R1, n, d-1, R2); // save R1 for future use TofftRep_trunc(R2, P1, F.l, 2*n-3); mul(R2, R2, F.HRep); FromfftRep(P1, R2, n-2, 2*n-4); TofftRep_trunc(R2, P1, F.k, len); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F) { long da, d, n, k; da = deg(a); n = F.n; if (n < 0) LogicError("SqrMod: uninitialized modulus"); if (da >= n) LogicError("bad args to SqrMod(zz_pX,zz_pX,zz_pXModulus)"); if (!F.UseFFT || da <= NTL_zz_pX_MUL_CROSSOVER) { zz_pX P1; sqr(P1, a); rem(x, P1, F); return; } d = 2*da + 1; k = NextPowerOfTwo(d); k = max(k, F.k); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); long len; if (zz_p::IsFFTPrime()) len = n; else len = 1L << F.k; TofftRep_trunc(R1, a, k, max(1L << F.k, d)); mul(R1, R1, R1); NDFromfftRep(P1, R1, n, d-1, R2); // save R1 for future use TofftRep_trunc(R2, P1, F.l, 2*n-3); mul(R2, R2, F.HRep); FromfftRep(P1, R2, n-2, 2*n-4); TofftRep_trunc(R2, P1, F.k, len); mul(R2, R2, F.FRep); reduce(R1, R1, F.k); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void PlainInvTrunc(zz_pX& x, const zz_pX& a, long m) /* x = (1/a) % X^m, input not output, constant term a is nonzero */ { long i, k, n, lb; zz_p v, t; zz_p s; const zz_p* ap; zz_p* xp; n = deg(a); if (n < 0) ArithmeticError("division by zero"); inv(s, ConstTerm(a)); if (n == 0) { conv(x, s); return; } ap = a.rep.elts(); x.rep.SetLength(m); xp = x.rep.elts(); xp[0] = s; long is_one = IsOne(s); for (k = 1; k < m; k++) { clear(v); lb = max(k-n, 0); for (i = lb; i <= k-1; i++) { mul(t, xp[i], ap[k-i]); add(v, v, t); } xp[k] = v; negate(xp[k], xp[k]); if (!is_one) mul(xp[k], xp[k], s); } x.normalize(); } void trunc(zz_pX& x, const zz_pX& a, long m) // x = a % X^m, output may alias input { if (m < 0) LogicError("trunc: bad args"); if (&x == &a) { if (x.rep.length() > m) { x.rep.SetLength(m); x.normalize(); } } else { long n; long i; zz_p* xp; const zz_p* ap; n = min(a.rep.length(), m); x.rep.SetLength(n); xp = x.rep.elts(); ap = a.rep.elts(); for (i = 0; i < n; i++) xp[i] = ap[i]; x.normalize(); } } void CyclicReduce(zz_pX& x, const zz_pX& a, long m) // computes x = a mod X^m-1 { long n = deg(a); long i, j; long accum; long p = zz_p::modulus(); if (n < m) { x = a; return; } if (&x != &a) x.rep.SetLength(m); for (i = 0; i < m; i++) { accum = rep(a.rep[i]); for (j = i + m; j <= n; j += m) accum = AddMod(accum, rep(a.rep[j]), p); x.rep[i].LoopHole() = accum; } if (&x == &a) x.rep.SetLength(m); x.normalize(); } void InvTrunc(zz_pX& x, const zz_pX& a, long m) { if (m < 0) LogicError("InvTrunc: bad args"); if (m == 0) { clear(x); return; } if (NTL_OVERFLOW(m, 1, 0)) ResourceError("overflow in InvTrunc"); if (&x == &a) { zz_pX la; la = a; if (m > NTL_zz_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, la, m); else PlainInvTrunc(x, la, m); } else { if (m > NTL_zz_pX_NEWTON_CROSSOVER && deg(a) > 0) NewtonInvTrunc(x, a, m); else PlainInvTrunc(x, a, m); } } void build(zz_pXModulus& x, const zz_pX& f) { x.f = f; x.n = deg(f); x.tracevec.make(); if (x.n <= 0) LogicError("build: deg(f) must be at least 1"); if (x.n <= NTL_zz_pX_MOD_CROSSOVER + 1) { x.UseFFT = 0; return; } x.UseFFT = 1; x.k = NextPowerOfTwo(x.n); x.l = NextPowerOfTwo(2*x.n - 3); TofftRep(x.FRep, f, x.k); zz_pX P1(INIT_SIZE, x.n+1), P2(INIT_SIZE, x.n); CopyReverse(P1, f, 0, x.n); InvTrunc(P2, P1, x.n-1); CopyReverse(P1, P2, 0, x.n-2); TofftRep(x.HRep, P1, x.l); } zz_pXModulus::zz_pXModulus(const zz_pX& ff) { build(*this, ff); } zz_pXMultiplier::zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F) { build(*this, b, F); } void build(zz_pXMultiplier& x, const zz_pX& b, const zz_pXModulus& F) { long db; long n = F.n; if (n < 0) LogicError("build zz_pXMultiplier: uninitialized modulus"); x.b = b; db = deg(b); if (db >= n) LogicError("build zz_pXMultiplier: deg(b) >= deg(f)"); if (!F.UseFFT || db <= NTL_zz_pX_MOD_CROSSOVER) { x.UseFFT = 0; return; } x.UseFFT = 1; fftRep R1(INIT_SIZE, F.l); zz_pX P1(INIT_SIZE, n); TofftRep_trunc(R1, b, F.l, 2*n-2); reduce(x.B2, R1, F.k); mul(R1, R1, F.HRep); FromfftRep(P1, R1, n-1, 2*n-3); TofftRep(x.B1, P1, F.l); // could be truncated to length max(1L << F.k, 2*n-2), except // for the usage in UpdateMap, where we would have to investigate // further } void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { long n = F.n; long da; da = deg(a); if (da >= n) LogicError(" bad args to MulMod(zz_pX,zz_pX,zz_pXMultiplier,zz_pXModulus)"); if (da < 0) { clear(x); return; } if (!B.UseFFT || !F.UseFFT || da <= NTL_zz_pX_MOD_CROSSOVER) { zz_pX P1; mul(P1, a, B.b); rem(x, P1, F); return; } zz_pX P1(INIT_SIZE, n), P2(INIT_SIZE, n); fftRep R1(INIT_SIZE, F.l), R2(INIT_SIZE, F.l); long len; if (zz_p::IsFFTPrime()) len = n; else len = 1L << F.k; TofftRep_trunc(R1, a, F.l, max(1L << F.k, 2*n-2)); mul(R2, R1, B.B1); FromfftRep(P1, R2, n-1, 2*n-3); reduce(R1, R1, F.k); mul(R1, R1, B.B2); TofftRep_trunc(R2, P1, F.k, len); mul(R2, R2, F.FRep); sub(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void PowerXMod(zz_pX& hh, const ZZ& e, const zz_pXModulus& F) { if (F.n < 0) LogicError("PowerXMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } long n = NumBits(e); long i; zz_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) MulByXMod(h, h, F.f); } if (e < 0) InvMod(h, h, F); hh = h; } void PowerXPlusAMod(zz_pX& hh, zz_p a, const ZZ& e, const zz_pXModulus& F) { if (F.n < 0) LogicError("PowerXPlusAMod: uninitialized modulus"); if (IsZero(e)) { set(hh); return; } zz_pX t1(INIT_SIZE, F.n), t2(INIT_SIZE, F.n); long n = NumBits(e); long i; zz_pX h; h.SetMaxLength(F.n); set(h); for (i = n - 1; i >= 0; i--) { SqrMod(h, h, F); if (bit(e, i)) { MulByXMod(t1, h, F.f); mul(t2, h, a); add(h, t1, t2); } } if (e < 0) InvMod(h, h, F); hh = h; } void PowerMod(zz_pX& h, const zz_pX& g, const ZZ& e, const zz_pXModulus& F) { if (deg(g) >= F.n) LogicError("PowerMod: bad args"); if (IsZero(e)) { set(h); return; } zz_pXMultiplier G; zz_pX res; long n = NumBits(e); long i; build(G, g, F); res.SetMaxLength(F.n); set(res); for (i = n - 1; i >= 0; i--) { SqrMod(res, res, F); if (bit(e, i)) MulMod(res, res, G, F); } if (e < 0) InvMod(res, res, F); h = res; } void NewtonInvTrunc(zz_pX& x, const zz_pX& a, long m) { x.SetMaxLength(m); long i; long t; t = NextPowerOfTwo(2*m-1); fftRep R1(INIT_SIZE, t), R2(INIT_SIZE, t); zz_pX P1(INIT_SIZE, m); long log2_newton = NextPowerOfTwo(NTL_zz_pX_NEWTON_CROSSOVER)-1; PlainInvTrunc(x, a, 1L << log2_newton); long k = 1L << log2_newton; long a_len = min(m, a.rep.length()); while (k < m) { long l = min(2*k, m); t = NextPowerOfTwo(2*k); TofftRep(R1, x, t); mul(R1, R1, R1); FromfftRep(P1, R1, 0, l-1); t = NextPowerOfTwo(deg(P1) + min(l, a_len)); TofftRep(R1, P1, t); TofftRep(R2, a, t, 0, min(l, a_len)-1); mul(R1, R1, R2); FromfftRep(P1, R1, k, l-1); x.rep.SetLength(l); long y_len = P1.rep.length(); for (i = k; i < l; i++) { if (i-k >= y_len) clear(x.rep[i]); else negate(x.rep[i], P1.rep[i-k]); } x.normalize(); k = l; } } void FFTDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { clear(q); r = a; return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); DivRem(q, r, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k1, k); fftRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; TofftRep(R1, b, k1); TofftRep(R2, P3, k1); mul(R1, R1, R2); FromfftRep(P1, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P1); q = P3; } void FFTDiv(zz_pX& q, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k; if (m < n) { clear(q); return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); div(q, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(q, R1, m-n, 2*(m-n)); } void FFTRem(zz_pX& r, const zz_pX& a, const zz_pX& b) { long n = deg(b); long m = deg(a); long k, l; if (m < n) { r = a; return; } if (m >= 3*n) { zz_pXModulus B; build(B, b); rem(r, a, B); return; } zz_pX P1, P2, P3; CopyReverse(P3, b, 0, n); InvTrunc(P2, P3, m-n+1); CopyReverse(P1, P2, 0, m-n); k = NextPowerOfTwo(2*(m-n)+1); long k1 = NextPowerOfTwo(n); long mx = max(k, k1); fftRep R1(INIT_SIZE, mx), R2(INIT_SIZE, mx); TofftRep(R1, P1, k); TofftRep(R2, a, k, n, m); mul(R1, R1, R2); FromfftRep(P3, R1, m-n, 2*(m-n)); l = 1L << k1; TofftRep(R1, b, k1); TofftRep(R2, P3, k1); mul(R1, R1, R2); FromfftRep(P3, R1, 0, n-1); CyclicReduce(P2, a, l); trunc(r, P2, n); sub(r, r, P3); } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTDivRem(q, r, a, b); else PlainDivRem(q, r, a, b); } void div(zz_pX& q, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTDiv(q, a, b); else PlainDiv(q, a, b); } void div(zz_pX& q, const zz_pX& a, zz_p b) { zz_p t; inv(t, b); mul(q, a, t); } void rem(zz_pX& r, const zz_pX& a, const zz_pX& b) { if (deg(b) > NTL_zz_pX_DIV_CROSSOVER && deg(a) - deg(b) > NTL_zz_pX_DIV_CROSSOVER) FFTRem(r, a, b); else PlainRem(r, a, b); } long operator==(const zz_pX& a, long b) { if (b == 0) return IsZero(a); if (b == 1) return IsOne(a); long da = deg(a); if (da > 0) return 0; zz_p bb; bb = b; if (da < 0) return IsZero(bb); return a.rep[0] == bb; } long operator==(const zz_pX& a, zz_p b) { if (IsZero(b)) return IsZero(a); long da = deg(a); if (da != 0) return 0; return a.rep[0] == b; } void power(zz_pX& x, const zz_pX& a, long e) { if (e < 0) { ArithmeticError("power: negative exponent"); } if (e == 0) { x = 1; return; } if (a == 0 || a == 1) { x = a; return; } long da = deg(a); if (da == 0) { x = power(ConstTerm(a), e); return; } if (da > (NTL_MAX_LONG-1)/e) ResourceError("overflow in power"); zz_pX res; res.SetMaxLength(da*e + 1); res = 1; long k = NumBits(e); long i; for (i = k - 1; i >= 0; i--) { sqr(res, res); if (bit(e, i)) mul(res, res, a); } x = res; } void reverse(zz_pX& x, const zz_pX& a, long hi) { if (hi < 0) { clear(x); return; } if (NTL_OVERFLOW(hi, 1, 0)) ResourceError("overflow in reverse"); if (&x == &a) { zz_pX tmp; CopyReverse(tmp, a, 0, hi); x = tmp; } else CopyReverse(x, a, 0, hi); } NTL_END_IMPL ntl-11.5.1/src/lzz_pX1.cpp0000644417616742025610000011341014064716022017017 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL long divide(zz_pX& q, const zz_pX& a, const zz_pX& b) { if (IsZero(b)) { if (IsZero(a)) { clear(q); return 1; } else return 0; } zz_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; q = lq; return 1; } long divide(const zz_pX& a, const zz_pX& b) { if (IsZero(b)) return IsZero(a); zz_pX lq, r; DivRem(lq, r, a, b); if (!IsZero(r)) return 0; return 1; } void zz_pXMatrix::operator=(const zz_pXMatrix& M) { elts[0][0] = M.elts[0][0]; elts[0][1] = M.elts[0][1]; elts[1][0] = M.elts[1][0]; elts[1][1] = M.elts[1][1]; } void RightShift(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) ResourceError("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); } void LeftShift(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) clear(x); else RightShift(x, a, -n); return; } if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in LeftShift"); long m = a.rep.length(); x.rep.SetLength(m+n); long i; for (i = m-1; i >= 0; i--) x.rep[i+n] = a.rep[i]; for (i = 0; i < n; i++) clear(x.rep[i]); } void ShiftAdd(zz_pX& U, const zz_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) add(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void ShiftSub(zz_pX& U, const zz_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); } void mul(zz_pX& U, zz_pX& V, const zz_pXMatrix& M) // (U, V)^T = M*(U, V)^T { long d = deg(U) - deg(M(1,1)); long k = NextPowerOfTwo(d - 1); // When the GCD algorithm is run on polynomials of degree n, n-1, // where n is a power of two, then d-1 is likely to be a power of two. // It would be more natural to set k = NextPowerOfTwo(d+1), but this // would be much less efficient in this case. long n = (1L << k); long xx; zz_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0; zz_p t1, t2; if (n == d-1) xx = 1; else if (n == d) xx = 2; else xx = 3; switch (xx) { case 1: GetCoeff(a0, M(0,0), 0); GetCoeff(a1, M(0,0), 1); GetCoeff(b0, M(0,1), 0); GetCoeff(b1, M(0,1), 1); GetCoeff(c0, M(1,0), 0); GetCoeff(d0, M(1,1), 0); GetCoeff(u0, U, 0); GetCoeff(u1, U, 1); GetCoeff(v0, V, 0); GetCoeff(v1, V, 1); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; mul(t1, (a1), (u0)); mul(t2, (a0), (u1)); add(t1, t1, t2); mul(t2, (b1), (v0)); add(t1, t1, t2); mul(t2, (b0), (v1)); add(t1, t1, t2); nu1 = t1; mul(t1, (c0), (u0)); mul(t2, (d0), (v0)); add (t1, t1, t2); nv0 = t1; break; case 2: GetCoeff(a0, M(0,0), 0); GetCoeff(b0, M(0,1), 0); GetCoeff(u0, U, 0); GetCoeff(v0, V, 0); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; break; case 3: break; } fftRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(RU, U, k); TofftRep(RV, V, k); TofftRep(R1, M(0,0), k); mul(R1, R1, RU); TofftRep(R2, M(0,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(U, R1, 0, d); TofftRep(R1, M(1,0), k); mul(R1, R1, RU); TofftRep(R2, M(1,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(V, R1, 0, d-1); // now fix-up results switch (xx) { case 1: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d-1, u0); SetCoeff(U, 0, nu0); GetCoeff(u1, U, 1); sub(u1, u1, nu1); SetCoeff(U, d, u1); SetCoeff(U, 1, nu1); GetCoeff(v0, V, 0); sub(v0, v0, nv0); SetCoeff(V, d-1, v0); SetCoeff(V, 0, nv0); break; case 2: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d, u0); SetCoeff(U, 0, nu0); break; } } void mul(zz_pXMatrix& A, zz_pXMatrix& B, zz_pXMatrix& C) // A = B*C, B and C are destroyed { long db = deg(B(1,1)); long dc = deg(C(1,1)); long da = db + dc; long k = NextPowerOfTwo(da+1); fftRep B00, B01, B10, B11, C0, C1, T1, T2; TofftRep(B00, B(0,0), k); B(0,0).kill(); TofftRep(B01, B(0,1), k); B(0,1).kill(); TofftRep(B10, B(1,0), k); B(1,0).kill(); TofftRep(B11, B(1,1), k); B(1,1).kill(); TofftRep(C0, C(0,0), k); C(0,0).kill(); TofftRep(C1, C(1,0), k); C(1,0).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,0), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,0), T1, 0, da); TofftRep(C0, C(0,1), k); C(0,1).kill(); TofftRep(C1, C(1,1), k); C(1,1).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,1), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,1), T1, 0, da); } void IterHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; zz_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void HalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; zz_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U1, V1, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U1, V1, d1); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; DivRem(Q, U1, U1, V1); swap(U1, V1); HalfGCD(M2, U1, V1, d2); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void XHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long du = deg(U); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { IterHalfGCD(M_out, U, V, d_red); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; DivRem(Q, U, U, V); swap(U, V); XHalfGCD(M2, U, V, d2); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void HalfGCD(zz_pX& U, zz_pX& V) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; HalfGCD(M1, U, V, d1); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); zz_pX Q; DivRem(Q, U, U, V); swap(U, V); HalfGCD(M1, U, V, d2); mul(U, V, M1); } void GCD(zz_pX& d, const zz_pX& u, const zz_pX& v) { zz_pX u1, v1; u1 = u; v1 = v; if (deg(u1) == deg(v1)) { if (IsZero(u1)) { clear(d); return; } rem(v1, v1, u1); } else if (deg(u1) < deg(v1)) { swap(u1, v1); } // deg(u1) > deg(v1) while (deg(u1) > NTL_zz_pX_GCD_CROSSOVER && !IsZero(v1)) { HalfGCD(u1, v1); if (!IsZero(v1)) { rem(u1, u1, v1); swap(u1, v1); } } PlainGCD(d, u1, v1); } void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b) { zz_p w; if (IsZero(a) && IsZero(b)) { clear(d); set(s); clear(t); return; } zz_pX U, V, Q; U = a; V = b; long flag = 0; if (deg(U) == deg(V)) { DivRem(Q, U, U, V); swap(U, V); flag = 1; } else if (deg(U) < deg(V)) { swap(U, V); flag = 2; } zz_pXMatrix M; XHalfGCD(M, U, V, deg(U)+1); d = U; if (flag == 0) { s = M(0,0); t = M(0,1); } else if (flag == 1) { s = M(0,1); mul(t, Q, M(0,1)); sub(t, M(0,0), t); } else { /* flag == 2 */ s = M(0,1); t = M(0,0); } // normalize inv(w, LeadCoeff(d)); mul(d, d, w); mul(s, s, w); mul(t, t, w); } void IterBuild(zz_p* a, long n) { long i, k; zz_p b, t; if (n <= 0) return; negate(a[0], a[0]); for (k = 1; k <= n-1; k++) { negate(b, a[k]); add(a[k], b, a[k-1]); for (i = k-1; i >= 1; i--) { mul(t, a[i], b); add(a[i], t, a[i-1]); } mul(a[0], a[0], b); } } void mul(zz_p* x, const zz_p* a, const zz_p* b, long n) { zz_p t, accum; long i, j, jmin, jmax; long d = 2*n-1; for (i = 0; i <= d; i++) { jmin = max(0, i-(n-1)); jmax = min(n-1, i); clear(accum); for (j = jmin; j <= jmax; j++) { mul(t, (a[j]), (b[i-j])); add(accum, accum, t); } if (i >= n) { add(accum, accum, (a[i-n])); add(accum, accum, (b[i-n])); } x[i] = accum; } } void BuildFromRoots(zz_pX& x, const vec_zz_p& a) { long n = a.length(); if (n == 0) { set(x); return; } long k0 = NextPowerOfTwo(NTL_zz_pX_MUL_CROSSOVER)-1; long crossover = 1L << k0; if (n <= NTL_zz_pX_MUL_CROSSOVER) { x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); return; } long k = NextPowerOfTwo(n); long m = 1L << k; long i, j; long l, width; zz_pX b(INIT_SIZE, m+1); b.rep = a; b.rep.SetLength(m+1); for (i = n; i < m; i++) clear(b.rep[i]); set(b.rep[m]); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); zz_p t1, one; set(one); vec_zz_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover); zz_p *g = G.elts(); zz_p *h = H.elts(); zz_p *tmp; for (i = 0; i < m; i+= crossover) { for (j = 0; j < crossover; j++) negate(g[j], b.rep[i+j]); if (k0 > 0) { for (j = 0; j < crossover; j+=2) { mul(t1, g[j], g[j+1]); add(g[j+1], g[j], g[j+1]); g[j] = t1; } } for (l = 1; l < k0; l++) { width = 1L << l; for (j = 0; j < crossover; j += 2*width) mul(&h[j], &g[j], &g[j+width], width); tmp = g; g = h; h = tmp; } for (j = 0; j < crossover; j++) b.rep[i+j] = g[j]; } for (l = k0; l < k; l++) { width = 1L << l; for (i = 0; i < m; i += 2*width) { t1 = b.rep[i+width]; set(b.rep[i+width]); TofftRep(R1, b, l+1, i, i+width); b.rep[i+width] = t1; t1 = b.rep[i+2*width]; set(b.rep[i+2*width]); TofftRep(R2, b, l+1, i+width, i+2*width); b.rep[i+2*width] = t1; mul(R1, R1, R2); FromfftRep(&b.rep[i], R1, 0, 2*width-1); sub(b.rep[i], b.rep[i], one); } } x.rep.SetLength(n+1); long delta = m-n; for (i = 0; i <= n; i++) x.rep[i] = b.rep[i+delta]; // no need to normalize } void eval(zz_p& b, const zz_pX& f, zz_p a) // does a Horner evaluation { zz_p acc; long i; clear(acc); for (i = deg(f); i >= 0; i--) { mul(acc, acc, a); add(acc, acc, f.rep[i]); } b = acc; } void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a) // naive algorithm: repeats Horner { if (&b == &f.rep) { vec_zz_p bb; eval(bb, f, a); b = bb; return; } long m = a.length(); b.SetLength(m); long i; for (i = 0; i < m; i++) eval(b[i], f, a[i]); } void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b) { long m = a.length(); if (b.length() != m) LogicError("interpolate: vector length mismatch"); if (m == 0) { clear(f); return; } vec_zz_p prod; prod = a; zz_p t1, t2; long k, i; vec_zz_p res; res.SetLength(m); for (k = 0; k < m; k++) { const zz_p& aa = a[k]; set(t1); for (i = k-1; i >= 0; i--) { mul(t1, t1, aa); add(t1, t1, prod[i]); } clear(t2); for (i = k-1; i >= 0; i--) { mul(t2, t2, aa); add(t2, t2, res[i]); } inv(t1, t1); sub(t2, b[k], t2); mul(t1, t1, t2); for (i = 0; i < k; i++) { mul(t2, prod[i], t1); add(res[i], res[i], t2); } res[k] = t1; if (k < m-1) { if (k == 0) negate(prod[0], prod[0]); else { negate(t1, a[k]); add(prod[k], t1, prod[k-1]); for (i = k-1; i >= 1; i--) { mul(t2, prod[i], t1); add(prod[i], t2, prod[i-1]); } mul(prod[0], prod[0], t1); } } } while (m > 0 && IsZero(res[m-1])) m--; res.SetLength(m); f.rep = res; } void InnerProduct(zz_pX& x, const vec_zz_p& v, long low, long high, const vec_zz_pX& H, long n, vec_zz_p& t) { zz_p s; long i, j; zz_p *tp = t.elts(); for (j = 0; j < n; j++) clear(tp[j]); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_p& h = H[i-low].rep; long m = h.length(); zz_p w = (v[i]); long W = rep(w); mulmod_precon_t Wpinv = PrepMulModPrecon(W, p, pinv); const zz_p *hp = h.elts(); for (j = 0; j < m; j++) { long S = MulModPrecon(rep(hp[j]), W, p, Wpinv); S = AddMod(S, rep(tp[j]), p); tp[j].LoopHole() = S; } } x.rep = t; x.normalize(); } void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& A, const zz_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } zz_pX s, t; vec_zz_p scratch(INIT_SIZE, F.n); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; zz_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; } void build(zz_pXArgument& A, const zz_pX& h, const zz_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) LogicError("build: bad args"); if (m > F.n) m = F.n; long i; if (zz_pXArgBound > 0) { double sz = 1; sz = sz*F.n; sz = sz+6; sz = sz*(sizeof (long)); sz = sz/1024; m = min(m, long(zz_pXArgBound/sz)); m = max(m, 1); } zz_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); } NTL_CHEAP_THREAD_LOCAL long zz_pXArgBound = 0; void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F) // x = g(h) mod f { long m = SqrRoot(g.rep.length()); if (m == 0) { clear(x); return; } zz_pXNewArgument A; build(A, h, F, m); CompMod(x, g, A, F); } void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length()); if (m == 0) { clear(x1); clear(x2); return; } zz_pXNewArgument A; build(A, h, F, m); zz_pX xx1, xx2; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); x1 = xx1; x2 = xx2; } void Comp3Mod(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F) { long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length()); if (m == 0) { clear(x1); clear(x2); clear(x3); return; } zz_pXNewArgument A; build(A, h, F, m); zz_pX xx1, xx2, xx3; CompMod(xx1, g1, A, F); CompMod(xx2, g2, A, F); CompMod(xx3, g3, A, F); x1 = xx1; x2 = xx2; x3 = xx3; } static void StripZeroes(vec_zz_p& x) { long n = x.length(); while (n > 0 && IsZero(x[n-1])) n--; x.SetLength(n); } void PlainUpdateMap(vec_zz_p& xx, const vec_zz_p& a, const zz_pX& b, const zz_pX& f) { long n = deg(f); long i, m; if (IsZero(b)) { xx.SetLength(0); return; } m = n-1 - deg(b); vec_zz_p x(INIT_SIZE, n); for (i = 0; i <= m; i++) InnerProduct(x[i], a, b.rep, i); if (deg(b) != 0) { zz_pX c(INIT_SIZE, n); LeftShift(c, b, m); for (i = m+1; i < n; i++) { MulByXMod(c, c, f); InnerProduct(x[i], a, c.rep); } } xx = x; } void UpdateMap(vec_zz_p& x, const vec_zz_p& aa, const zz_pXMultiplier& B, const zz_pXModulus& F) { long n = F.n; vec_zz_p a; a = aa; StripZeroes(a); if (a.length() > n) LogicError("UpdateMap: bad args"); long i; if (!B.UseFFT) { PlainUpdateMap(x, a, B.b, F.f); StripZeroes(x); return; } fftRep R1(INIT_SIZE, F.k), R2(INIT_SIZE, F.l); vec_zz_p V1(INIT_SIZE, n); RevTofftRep(R1, a, F.k, 0, a.length()-1, 0); mul(R2, R1, F.FRep); RevFromfftRep(V1, R2, 0, n-2); for (i = 0; i <= n-2; i++) negate(V1[i], V1[i]); RevTofftRep(R2, V1, F.l, 0, n-2, n-1); mul(R2, R2, B.B1); mul(R1, R1, B.B2); AddExpand(R2, R1); RevFromfftRep(x, R2, 0, n-1); StripZeroes(x); } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.H.length()-1; long l = (k+m-1)/m - 1; zz_pXMultiplier M; build(M, H.H[m], F); vec_zz_p s(INIT_SIZE, n); s = a; StripZeroes(s); x.SetLength(k); for (long i = 0; i <= l; i++) { long m1 = min(m, k-i*m); zz_p* w = &x[i*m]; for (long j = 0; j < m1; j++) InnerProduct(w[j], H.H[j].rep, s); if (i < l) UpdateMap(s, s, M, F); } } // zz_pXNewArgument stuff void build(zz_pXNewArgument& H, const zz_pX& h, const zz_pXModulus& F, long m) { long n = F.n; if (m <= 0 || deg(h) >= n) LogicError("build: bad args"); if (NTL_OVERFLOW(m, 1, 0)) ResourceError("zz_pXNewArgument:build: m too big"); // NOTE: we don't take zz_pXArgBound into account, as the // new strategy anyway always uses space about (m + deg(g)/m)*n long width; // usually n, but may be smaller if h has very low degree // some messiness here to avoid overflow long dh = deg(h); if (dh < 0) width = 1; else if (dh == 0 || m-1 == 0) width = 1; else if (dh <= n/(m-1)) width = min(n, dh*(m-1) + 1); else width = n; zz_pXMultiplier M; build(M, h, F); Mat mat; mat.SetDims(m, width); zz_pX poly; poly = 1; for (long i = 0; i < m; i++) { VectorCopy(mat[i], poly, width); MulMod(poly, poly, M, F); } mat.swap(H.mat); poly.swap(H.poly); } void CompMod(zz_pX& x, const zz_pX& g, const zz_pXNewArgument& H, const zz_pXModulus& F) { long d = deg(g)+1; if (d <= 1) { x = g; return; } long m = H.mat.NumRows(); if (m == 0) LogicError("CompMod: uninitialized argument"); long l = (d+m-1)/m; Mat gmat; gmat.SetDims(l, m); for (long i = 0; i < l; i++) for (long j = 0; j < m; j++) gmat[i][j] = coeff(g, i*m+j); Mat xmat; mul(xmat, gmat, H.mat); zz_pX t; conv(t, xmat[l-1]); if (l-2 >= 0) { zz_pXMultiplier M; build(M, H.poly, F); zz_pX s; for (long i = l-2; i >= 0; i--) { conv(s, xmat[i]); MulMod(t, t, M, F); add(t, t, s); } } x = t; } void reduce(zz_pXNewArgument& H, const zz_pXModulus& F) { long m = H.mat.NumRows(); if (m == 0) LogicError("reduce: uninitialized argument"); zz_pX h; if (m > 1) conv(h, H.mat[1]); else h = H.poly; rem(h, h, F); build(H, h, F, m); } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXNewArgument& H, const zz_pXModulus& F) { long n = F.n; if (a.length() > n || k < 0) LogicError("ProjectPowers: bad args"); if (NTL_OVERFLOW(k, 1, 0)) ResourceError("ProjectPowers: excessive args"); long m = H.mat.NumRows(); if (m == 0) LogicError("CompMod: uninitialized argument"); long width = H.mat.NumCols(); long l = (k+m-1)/m; Mat hmat, amat, xmat; transpose(hmat, H.mat); // NOTE: it would be better if we could compute // matrix*transpose(matrix), and avoid this // transposition altogether // NOTE: if we want to save on some memory usage, // we could kill H.mat at this point amat.SetDims(l, width); vec_zz_p s(INIT_SIZE, n); s = a; StripZeroes(s); VectorCopy(amat[0], s, width); if (l > 1) { zz_pXMultiplier M; build(M, H.poly, F); for (long i = 1; i < l; i++) { UpdateMap(s, s, M, F); VectorCopy(amat[i], s, width); } } mul(xmat, amat, hmat); x.SetLength(k); for (long i = 0; i < l; i++) { long j_max = min(m, k-i*m); for (long j = 0; j < j_max; j++) x[i*m+j] = xmat[i][j]; } } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F) { if (a.length() > F.n || k < 0) LogicError("ProjectPowers: bad args"); if (k == 0) { x.SetLength(0); return; } long m = SqrRoot(k); zz_pXNewArgument H; build(H, h, F, m); ProjectPowers(x, a, k, H, F); } void BerlekampMassey(zz_pX& h, const vec_zz_p& a, long m) { zz_pX Lambda, Sigma, Temp; long L; zz_p Delta, Delta1, t1; long shamt; // cerr << "*** " << m << "\n"; Lambda.SetMaxLength(m+1); Sigma.SetMaxLength(m+1); Temp.SetMaxLength(m+1); L = 0; set(Lambda); clear(Sigma); set(Delta); shamt = 0; long i, r, dl; for (r = 1; r <= 2*m; r++) { // cerr << r << "--"; clear(Delta1); dl = deg(Lambda); for (i = 0; i <= dl; i++) { mul(t1, Lambda.rep[i], a[r-i-1]); add(Delta1, Delta1, t1); } if (IsZero(Delta1)) { shamt++; // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else if (2*L < r) { div(t1, Delta1, Delta); mul(Temp, Sigma, t1); Sigma = Lambda; ShiftSub(Lambda, Temp, shamt+1); shamt = 0; L = r-L; Delta = Delta1; // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } else { shamt++; div(t1, Delta1, Delta); mul(Temp, Sigma, t1); ShiftSub(Lambda, Temp, shamt); // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n"; } } // cerr << "finished: " << L << " " << deg(Lambda) << "\n"; dl = deg(Lambda); h.rep.SetLength(L + 1); for (i = 0; i < L - dl; i++) clear(h.rep[i]); for (i = L - dl; i <= L; i++) h.rep[i] = Lambda.rep[L - i]; } void GCDMinPolySeq(zz_pX& h, const vec_zz_p& x, long m) { long i; zz_pX a, b; zz_pXMatrix M; zz_p t; a.rep.SetLength(2*m); for (i = 0; i < 2*m; i++) a.rep[i] = x[2*m-1-i]; a.normalize(); SetCoeff(b, 2*m); HalfGCD(M, b, a, m+1); /* make monic */ inv(t, LeadCoeff(M(1,1))); mul(h, M(1,1), t); } void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m) { if (m < 0 || NTL_OVERFLOW(m, 1, 0)) LogicError("MinPoly: bad args"); if (a.length() < 2*m) LogicError("MinPoly: sequence too short"); if (m > NTL_zz_pX_BERMASS_CROSSOVER) GCDMinPolySeq(h, a, m); else BerlekampMassey(h, a, m); } void DoMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m, const vec_zz_p& R) { vec_zz_p x; ProjectPowers(x, R, 2*m, g, F); MinPolySeq(h, x, m); } void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m) { long n = F.n; if (m < 1 || m > n) LogicError("ProbMinPoly: bad args"); long i; vec_zz_p R(INIT_SIZE, n); for (i = 0; i < n; i++) random(R[i]); DoMinPolyMod(h, g, F, m, R); } void MinPolyMod(zz_pX& hh, const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX h, h1; long n = F.n; if (m < 1 || m > n) LogicError("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; zz_pX h2, h3; zz_pXMultiplier H1; vec_zz_p R(INIT_SIZE, n); for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, H1, F); if (IsZero(h1)) { hh = h; return; } } } void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m) { vec_zz_p R(INIT_SIZE, 1); if (m < 1 || m > F.n) LogicError("IrredPoly: bad args"); set(R[0]); DoMinPolyMod(h, g, F, m, R); } void diff(zz_pX& x, const zz_pX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); } void MakeMonic(zz_pX& x) { if (IsZero(x)) return; if (IsOne(LeadCoeff(x))) return; zz_p t; inv(t, LeadCoeff(x)); mul(x, x, t); } void PlainMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { zz_pX y; mul(y, a, b); trunc(x, y, n); } void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long d = deg(a) + deg(b); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, a, k); TofftRep(R2, b, k); mul(R1, R1, R2); FromfftRep(x, R1, 0, n-1); } void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { if (n < 0) LogicError("MulTrunc: bad args"); if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER || deg(b) <= NTL_zz_pX_MUL_CROSSOVER) PlainMulTrunc(x, a, b, n); else FFTMulTrunc(x, a, b, n); } void PlainSqrTrunc(zz_pX& x, const zz_pX& a, long n) { zz_pX y; sqr(y, a); trunc(x, y, n); } void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } long d = 2*deg(a); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k); TofftRep(R1, a, k); mul(R1, R1, R1); FromfftRep(x, R1, 0, n-1); } void SqrTrunc(zz_pX& x, const zz_pX& a, long n) { if (n < 0) LogicError("SqrTrunc: bad args"); if (deg(a) <= NTL_zz_pX_MUL_CROSSOVER) PlainSqrTrunc(x, a, n); else FFTSqrTrunc(x, a, n); } void FastTraceVec(vec_zz_p& S, const zz_pX& f) { long n = deg(f); if (n <= 0) LogicError("FastTraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } if (n == 1) { S.SetLength(1); set(S[0]); return; } long i; zz_pX f1; f1.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) f1.rep[i] = f.rep[n-i]; f1.normalize(); zz_pX f2; f2.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) mul(f2.rep[i], f.rep[n-1-i], i+1); f2.normalize(); zz_pX f3; InvTrunc(f3, f1, n-1); MulTrunc(f3, f3, f2, n-1); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(f3, i-1)); } void PlainTraceVec(vec_zz_p& S, const zz_pX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); zz_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; zz_p acc, t; const zz_p *fp = f.rep.elts();; zz_p *sp = S.elts(); sp[0] = n; for (k = 1; k < n; k++) { mul(acc, fp[n-k], k); for (i = 1; i < k; i++) { mul(t, fp[n-i], rep(sp[k-i])); add(acc, acc, t); } negate(sp[k], acc); } } void TraceVec(vec_zz_p& S, const zz_pX& f) { if (deg(f) <= NTL_zz_pX_TRACE_CROSSOVER) PlainTraceVec(S, f); else FastTraceVec(S, f); } void ComputeTraceVec(vec_zz_p& S, const zz_pXModulus& F) { if (!F.UseFFT) { PlainTraceVec(S, F.f); return; } long i; long n = F.n; fftRep R; zz_pX P, g; g.rep.SetLength(n-1); for (i = 1; i < n; i++) mul(g.rep[n-i-1], F.f.rep[n-i], i); g.normalize(); TofftRep(R, g, F.l); mul(R, R, F.HRep); FromfftRep(P, R, n-2, 2*n-4); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(P, n-1-i)); } void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F) { long n = F.n; if (deg(a) >= n) LogicError("trace: bad args"); do { // NOTE: thread safe lazy init Lazy::Builder builder(F.tracevec.val()); if (!builder()) break; UniquePtr p; p.make(); ComputeTraceVec(*p, F); builder.move(p); } while (0); InnerProduct(x, a.rep, *F.tracevec.val()); } void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f) { if (deg(a) >= deg(f) || deg(f) <= 0) LogicError("trace: bad args"); project(x, TraceVec(f), a); } void PlainResultant(zz_p& rres, const zz_pX& a, const zz_pX& b) { zz_p res; if (IsZero(a) || IsZero(b)) clear(res); else if (deg(a) == 0 && deg(b) == 0) set(res); else { long d0, d1, d2; zz_p lc; set(res); long n = max(deg(a),deg(b)) + 1; zz_pX u(INIT_SIZE, n), v(INIT_SIZE, n); u = a; v = b; for (;;) { d0 = deg(u); d1 = deg(v); lc = LeadCoeff(v); PlainRem(u, u, v); swap(u, v); d2 = deg(v); if (d2 >= 0) { power(lc, lc, d0-d2); mul(res, res, lc); if (d0 & d1 & 1) negate(res, res); } else { if (d1 == 0) { power(lc, lc, d0); mul(res, res, lc); } else clear(res); break; } } } rres = res; } void ResIterHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red, vec_zz_p& cvec, vec_long& dvec) { M_out(0,0).SetMaxLength(d_red); M_out(0,1).SetMaxLength(d_red); M_out(1,0).SetMaxLength(d_red); M_out(1,1).SetMaxLength(d_red); set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); long goal = deg(U) - d_red; if (deg(V) <= goal) return; zz_pX Q, t(INIT_SIZE, d_red); while (deg(V) > goal) { append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); PlainDivRem(Q, U, U, V); swap(U, V); mul(t, Q, M_out(1,0)); sub(t, M_out(0,0), t); M_out(0,0) = M_out(1,0); M_out(1,0) = t; mul(t, Q, M_out(1,1)); sub(t, M_out(0,1), t); M_out(0,1) = M_out(1,1); M_out(1,1) = t; } } void ResHalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red, vec_zz_p& cvec, vec_long& dvec) { if (IsZero(V) || deg(V) <= deg(U) - d_red) { set(M_out(0,0)); clear(M_out(0,1)); clear(M_out(1,0)); set(M_out(1,1)); return; } long n = deg(U) - 2*d_red + 2; if (n < 0) n = 0; zz_pX U1, V1; RightShift(U1, U, n); RightShift(V1, V, n); if (d_red <= NTL_zz_pX_HalfGCD_CROSSOVER) { ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec); return; } long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; ResHalfGCD(M1, U1, V1, d1, cvec, dvec); mul(U1, V1, M1); long d2 = deg(V1) - deg(U) + n + d_red; if (IsZero(V1) || d2 <= 0) { M_out = M1; return; } zz_pX Q; zz_pXMatrix M2; append(cvec, LeadCoeff(V1)); append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1)); DivRem(Q, U1, U1, V1); swap(U1, V1); ResHalfGCD(M2, U1, V1, d2, cvec, dvec); zz_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,0)); sub(t, M1(0,0), t); swap(M1(0,0), M1(1,0)); swap(M1(1,0), t); t.kill(); t.SetMaxLength(deg(M1(1,1))+deg(Q)+1); mul(t, Q, M1(1,1)); sub(t, M1(0,1), t); swap(M1(0,1), M1(1,1)); swap(M1(1,1), t); t.kill(); mul(M_out, M2, M1); } void ResHalfGCD(zz_pX& U, zz_pX& V, vec_zz_p& cvec, vec_long& dvec) { long d_red = (deg(U)+1)/2; if (IsZero(V) || deg(V) <= deg(U) - d_red) { return; } long du = deg(U); long d1 = (d_red + 1)/2; if (d1 < 1) d1 = 1; if (d1 >= d_red) d1 = d_red - 1; zz_pXMatrix M1; ResHalfGCD(M1, U, V, d1, cvec, dvec); mul(U, V, M1); long d2 = deg(V) - du + d_red; if (IsZero(V) || d2 <= 0) { return; } M1(0,0).kill(); M1(0,1).kill(); M1(1,0).kill(); M1(1,1).kill(); zz_pX Q; append(cvec, LeadCoeff(V)); append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V)); DivRem(Q, U, U, V); swap(U, V); ResHalfGCD(M1, U, V, d2, cvec, dvec); mul(U, V, M1); } void resultant(zz_p& rres, const zz_pX& u, const zz_pX& v) { if (deg(u) <= NTL_zz_pX_GCD_CROSSOVER || deg(v) <= NTL_zz_pX_GCD_CROSSOVER) { PlainResultant(rres, u, v); return; } zz_pX u1, v1; u1 = u; v1 = v; zz_p res, t; set(res); if (deg(u1) == deg(v1)) { rem(u1, u1, v1); swap(u1, v1); if (IsZero(v1)) { clear(rres); return; } power(t, LeadCoeff(u1), deg(u1) - deg(v1)); mul(res, res, t); if (deg(u1) & 1) negate(res, res); } else if (deg(u1) < deg(v1)) { swap(u1, v1); if (deg(u1) & deg(v1) & 1) negate(res, res); } // deg(u1) > deg(v1) && v1 != 0 vec_zz_p cvec; vec_long dvec; cvec.SetMaxLength(deg(v1)+2); dvec.SetMaxLength(deg(v1)+2); append(cvec, LeadCoeff(u1)); append(dvec, deg(u1)); while (deg(u1) > NTL_zz_pX_GCD_CROSSOVER && !IsZero(v1)) { ResHalfGCD(u1, v1, cvec, dvec); if (!IsZero(v1)) { append(cvec, LeadCoeff(v1)); append(dvec, deg(v1)); rem(u1, u1, v1); swap(u1, v1); } } if (IsZero(v1) && deg(u1) > 0) { clear(rres); return; } long i, l; l = dvec.length(); if (deg(u1) == 0) { // we went all the way... for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]); mul(res, res, t); } else { for (i = 0; i <= l-3; i++) { power(t, cvec[i+1], dvec[i]-dvec[i+2]); mul(res, res, t); if (dvec[i] & dvec[i+1] & 1) negate(res, res); } power(t, cvec[l-1], dvec[l-2]-deg(v1)); mul(res, res, t); if (dvec[l-2] & dvec[l-1] & 1) negate(res, res); PlainResultant(t, u1, v1); mul(res, res, t); } rres = res; } void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f) { if (deg(f) <= 0 || deg(a) >= deg(f)) LogicError("norm: bad args"); if (IsZero(a)) { clear(x); return; } zz_p t; resultant(t, f, a); if (!IsOne(LeadCoeff(f))) { zz_p t1; power(t1, LeadCoeff(f), deg(a)); inv(t1, t1); mul(t, t, t1); } x = t; } NTL_END_IMPL ntl-11.5.1/src/lzz_pXCharPoly.cpp0000644417616742025610000000230114064716022020374 0ustar gid-shoupvpug-gid-shoupv#include NTL_START_IMPL static void HessCharPoly(zz_pX& g, const zz_pX& a, const zz_pX& f) { long n = deg(f); if (n <= 0 || deg(a) >= n) LogicError("HessCharPoly: bad args"); mat_zz_p M; M.SetDims(n, n); long i, j; zz_pX t; t = a; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = coeff(t, j); if (i < n-1) MulByXMod(t, t, f); } CharPoly(g, M); } void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& ff) { zz_pX f = ff; MakeMonic(f); long n = deg(f); if (n <= 0 || deg(a) >= n) LogicError("CharPoly: bad args"); if (IsZero(a)) { clear(g); SetCoeff(g, n); return; } if (n > 90 || (zz_p::PrimeCnt() <= 1 && n > 45)) { zz_pX h; MinPolyMod(h, a, f); if (deg(h) == n) { g = h; return; } } if (zz_p::modulus() < n+1) { HessCharPoly(g, a, f); return; } vec_zz_p u(INIT_SIZE, n+1), v(INIT_SIZE, n+1); zz_pX h, h1; negate(h, a); long i; for (i = 0; i <= n; i++) { u[i] = i; add(h1, h, u[i]); resultant(v[i], f, h1); } interpolate(g, u, v); } NTL_END_IMPL ntl-11.5.1/src/lzz_pXFactoring.cpp0000644417616742025610000010366114064716022020602 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& ff) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SquareFreeDecomp: bad args"); zz_pX r, t, v, tmp1; long m, j, finished, done; u.SetLength(0); if (deg(f) == 0) return; m = 1; finished = 0; do { j = 1; diff(tmp1, f); GCD(r, f, tmp1); div(t, f, r); if (deg(t) > 0) { done = 0; do { GCD(v, r, t); div(tmp1, t, v); if (deg(tmp1) > 0) append(u, cons(tmp1, j*m)); if (deg(v) > 0) { div(r, r, v); t = v; j++; } else done = 1; } while (!done); if (deg(r) == 0) finished = 1; } if (!finished) { /* r is a p-th power */ long p, k, d; p = long(zz_p::modulus()); d = deg(r)/p; f.rep.SetLength(d+1); for (k = 0; k <= d; k++) f.rep[k] = r.rep[k*p]; m = m*p; } } while (!finished); } static void NullSpace(long& r, vec_long& D, vec_vec_zz_p& M, long verbose) { long k, l, n; long i, j; long pos; zz_p t1, t2; zz_p *x, *y; n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long T1, T2; mulmod_precon_t T1pinv; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p inv(t1, M[l][k]); negate(t1, t1); for (j = k+1; j < n; j++) { mul(M[l][j], M[l][j], t1); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; T1 = rep(t1); T1pinv = PrepMulModPrecon(T1, p, pinv); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, T1pinv); T2 = AddMod(T2, rep(*x), p); (*x).LoopHole() = T2; } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } } static void BuildMatrix(mat_zz_p& M, long n, const zz_pX& g, const zz_pXModulus& F, long verbose) { zz_pXMultiplier G; zz_pX h; M.SetDims(n, n); build(G, g, F); set(h); for (long i = 0; i < n; i++) { if (verbose && i % 10 == 0) cerr << "+"; VectorCopy(M[i], h, n); if (i < n-1) MulMod(h, h, G, F); } for (long i = 0; i < n; i++) add(M[i][i], M[i][i], -1); } static void RecFindRoots(vec_zz_p& x, const zz_pX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } zz_pX h; zz_p r; long p1 = zz_p::modulus() >> 1; { zz_pXModulus F; build(F, f); do { random(r); PowerXPlusAMod(h, r, p1, F); add(h, h, -1); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); } void FindRoots(vec_zz_p& x, const zz_pX& ff) { zz_pX f = ff; x.SetMaxLength(deg(f)); x.SetLength(0); RecFindRoots(x, f); } static void RandomBasisElt(zz_pX& g, mat_zz_p& ker) { long r = ker.NumRows(); long n = ker.NumCols(); vec_zz_p v; v.SetLength(r); for (long i = 0; i < r; i++) random(v[i]); mul(g.rep, v, ker); g.normalize(); } static void split(zz_pX& f1, zz_pX& g1, zz_pX& f2, zz_pX& g2, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots, long lo, long mid) { long r = mid-lo+1; zz_pXModulus F; build(F, f); vec_zz_p lroots(INIT_SIZE, r); long i; for (i = 0; i < r; i++) lroots[i] = roots[lo+i]; zz_pX h, a, d; BuildFromRoots(h, lroots); CompMod(a, h, g, F); GCD(f1, a, f); div(f2, f, f1); rem(g1, g, f1); rem(g2, g, f2); } static void RecFindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots, long lo, long hi) { long r = hi-lo+1; if (r == 0) return; if (r == 1) { append(factors, f); return; } zz_pX f1, g1, f2, g2; long mid = (lo+hi)/2; split(f1, g1, f2, g2, f, g, roots, lo, mid); RecFindFactors(factors, f1, g1, roots, lo, mid); RecFindFactors(factors, f2, g2, roots, mid+1, hi); } static void FindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots) { long r = roots.length(); factors.SetMaxLength(r); factors.SetLength(0); RecFindFactors(factors, f, g, roots, 0, r-1); } #if 0 static void IterFindFactors(vec_zz_pX& factors, const zz_pX& f, const zz_pX& g, const vec_zz_p& roots) { long r = roots.length(); long i; zz_pX h; factors.SetLength(r); for (i = 0; i < r; i++) { sub(h, g, roots[i]); GCD(factors[i], f, h); } } #endif void SFBerlekamp(vec_zz_pX& factors, const zz_pX& ff, long verbose) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFBerlekamp: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } double t; long p; p = zz_p::modulus(); long n = deg(f); zz_pXModulus F; build(F, f); zz_pX g, h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(g, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } mat_zz_p M, ker; if (verbose) { cerr << "building matrix..."; t = GetTime(); } BuildMatrix(M, n, g, F, verbose); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "diagonalizing..."; t = GetTime(); } kernel(ker, M); if (verbose) { cerr << (GetTime()-t) << "\n"; } M.kill(); long r = ker.NumRows(); if (verbose) cerr << "number of factors = " << r << "\n"; if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (verbose) { cerr << "factor extraction..."; t = GetTime(); } vec_zz_p roots; RandomBasisElt(g, ker); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(factors, f, g, roots); zz_pX g1; vec_zz_pX S, S1; long i; while (factors.length() < r) { if (verbose) cerr << "+"; RandomBasisElt(g, ker); S.kill(); for (i = 0; i < factors.length(); i++) { const zz_pX& f = factors[i]; if (deg(f) == 1) { append(S, f); continue; } build(F, f); rem(g1, g, F); if (deg(g1) <= 0) { append(S, f); continue; } MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1)); FindRoots(roots, h); S1.kill(); FindFactors(S1, f, g1, roots); append(S, S1); } swap(factors, S); } if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "degrees:"; long i; for (i = 0; i < factors.length(); i++) cerr << " " << deg(factors[i]); cerr << "\n"; } } void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose) { double t; vec_pair_zz_pX_long sfd; vec_zz_pX x; if (!IsOne(LeadCoeff(f))) LogicError("berlekamp: bad args"); if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFBerlekamp(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } static void AddFactor(vec_pair_zz_pX_long& factors, const zz_pX& g, long d, long verbose) { if (verbose) cerr << "degree=" << d << ", number=" << deg(g)/d << "\n"; append(factors, cons(g, d)); } static void ProcessTable(zz_pX& f, vec_pair_zz_pX_long& factors, const zz_pXModulus& F, long limit, const vec_zz_pX& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; zz_pX t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); zz_pX t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); } void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b) { if (d < 0) LogicError("TraceMap: bad args"); zz_pX y, z, t; z = b; y = a; clear(w); while (d) { if (d == 1) { if (IsZero(w)) w = y; else { CompMod(w, w, z, F); add(w, w, y); } } else if ((d & 1) == 0) { Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else if (IsZero(w)) { w = y; Comp2Mod(z, t, z, y, z, F); add(y, t, y); } else { Comp3Mod(z, t, w, z, y, w, z, F); add(w, w, y); add(y, t, y); } d = d >> 1; } } void PowerCompose(zz_pX& y, const zz_pX& h, long q, const zz_pXModulus& F) { if (q < 0) LogicError("PowerCompose: bad args"); zz_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y); while (q) { sw = 0; if (q > 1) sw = 2; if (q & 1) { if (IsX(y)) y = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y, y, z, F); break; case 2: CompMod(z, z, z, F); break; case 3: Comp2Mod(y, z, y, z, z, F); break; } q = q >> 1; } } long ProbIrredTest(const zz_pX& f, long iter) { long n = deg(f); if (n <= 0) return 0; if (n == 1) return 1; long p; p = zz_p::modulus(); zz_pXModulus F; build(F, f); zz_pX b, r, s; PowerXMod(b, p, F); long i; for (i = 0; i < iter; i++) { random(r, n); TraceMap(s, r, n, F, b); if (deg(s) > 0) return 0; } if (p >= n) return 1; if (n % p != 0) return 1; PowerCompose(s, b, n/p, F); return !IsX(s); } NTL_CHEAP_THREAD_LOCAL long zz_pX_BlockingFactor = 10; void DDF(vec_pair_zz_pX_long& factors, const zz_pX& ff, const zz_pX& hh, long verbose) { zz_pX f = ff; zz_pX h = hh; if (!IsOne(LeadCoeff(f))) LogicError("DDF: bad args"); factors.SetLength(0); if (deg(f) == 0) return; if (deg(f) == 1) { AddFactor(factors, f, 1, verbose); return; } long CompTableSize = 2*SqrRoot(deg(f)); long GCDTableSize = zz_pX_BlockingFactor; zz_pXModulus F; build(F, f); zz_pXNewArgument H; build(H, h, F, min(CompTableSize, deg(f))); long i, d, limit, old_n; zz_pX g, X; vec_zz_pX tbl(INIT_SIZE, GCDTableSize); SetX(X); i = 0; g = h; d = 1; limit = GCDTableSize; while (2*d <= deg(f)) { old_n = deg(f); sub(tbl[i], g, X); i++; if (i == limit) { ProcessTable(f, factors, F, i, tbl, d, verbose); i = 0; } d = d + 1; if (2*d <= deg(f)) { // we need to go further if (deg(f) < old_n) { // f has changed build(F, f); rem(h, h, f); rem(g, g, f); build(H, h, F, min(CompTableSize, deg(f))); } CompMod(g, g, H, F); } } ProcessTable(f, factors, F, i, tbl, d-1, verbose); if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose); } void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose) { vec_zz_p roots; double t; if (verbose) { cerr << "finding roots..."; t = GetTime(); } FindRoots(roots, f); if (verbose) { cerr << (GetTime()-t) << "\n"; } long r = roots.length(); factors.SetLength(r); for (long j = 0; j < r; j++) { SetX(factors[j]); sub(factors[j], factors[j], roots[j]); } } static void EDFSplit(vec_zz_pX& v, const zz_pX& f, const zz_pX& b, long d) { zz_pX a, g, h; zz_pXModulus F; vec_zz_p roots; build(F, f); long n = F.n; long r = n/d; random(a, n); TraceMap(g, a, d, F, b); MinPolyMod(h, g, F, r); FindRoots(roots, h); FindFactors(v, f, g, roots); } static void RecEDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& b, long d, long verbose) { vec_zz_pX v; long i; if (verbose) cerr << "+"; EDFSplit(v, f, b, d); for (i = 0; i < v.length(); i++) { if (deg(v[i]) == d) { append(factors, v[i]); } else { zz_pX bb; rem(bb, b, v[i]); RecEDF(factors, v[i], bb, d, verbose); } } } void EDF(vec_zz_pX& factors, const zz_pX& ff, const zz_pX& bb, long d, long verbose) { zz_pX f = ff; zz_pX b = bb; if (!IsOne(LeadCoeff(f))) LogicError("EDF: bad args"); long n = deg(f); long r = n/d; if (r == 0) { factors.SetLength(0); return; } if (r == 1) { factors.SetLength(1); factors[0] = f; return; } if (d == 1) { RootEDF(factors, f, verbose); return; } double t; if (verbose) { cerr << "computing EDF(" << d << "," << r << ")..."; t = GetTime(); } factors.SetLength(0); RecEDF(factors, f, b, d, verbose); if (verbose) cerr << (GetTime()-t) << "\n"; } void SFCanZass1(vec_pair_zz_pX_long& u, zz_pX& h, const zz_pX& f, long verbose) { if (!IsOne(LeadCoeff(f)) || deg(f) == 0) LogicError("SFCanZass1: bad args"); double t; long p = zz_p::modulus(); zz_pXModulus F; build(F, f); if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } } void SFCanZass2(vec_zz_pX& factors, const vec_pair_zz_pX_long& u, const zz_pX& h, long verbose) { zz_pX hh; vec_zz_pX v; factors.SetLength(0); long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void SFCanZass(vec_zz_pX& factors, const zz_pX& ff, long verbose) { zz_pX f = ff; if (!IsOne(LeadCoeff(f))) LogicError("SFCanZass: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(1); factors[0] = f; return; } factors.SetLength(0); double t; long p = zz_p::modulus(); zz_pXModulus F; build(F, f); zz_pX h; if (verbose) { cerr << "computing X^p..."; t = GetTime(); } PowerXMod(h, p, F); if (verbose) { cerr << (GetTime()-t) << "\n"; } vec_pair_zz_pX_long u; if (verbose) { cerr << "computing DDF..."; t = GetTime(); } NewDDF(u, f, h, verbose); if (verbose) { t = GetTime()-t; cerr << "DDF time: " << t << "\n"; } zz_pX hh; vec_zz_pX v; long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long d = u[i].b; long r = deg(g)/d; if (r == 1) { // g is already irreducible append(factors, g); } else { // must perform EDF if (d == 1) { // root finding RootEDF(v, g, verbose); append(factors, v); } else { // general case rem(hh, h, g); EDF(v, g, hh, d, verbose); append(factors, v); } } } } void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("CanZass: bad args"); double t; vec_pair_zz_pX_long sfd; vec_zz_pX x; if (verbose) { cerr << "square-free decomposition..."; t = GetTime(); } SquareFreeDecomp(sfd, f); if (verbose) cerr << (GetTime()-t) << "\n"; factors.SetLength(0); long i, j; for (i = 0; i < sfd.length(); i++) { if (verbose) { cerr << "factoring multiplicity " << sfd[i].b << ", deg = " << deg(sfd[i].a) << "\n"; } SFCanZass(x, sfd[i].a, verbose); for (j = 0; j < x.length(); j++) append(factors, cons(x[j], sfd[i].b)); } } void mul(zz_pX& f, const vec_pair_zz_pX_long& v) { long i, j, n; n = 0; for (i = 0; i < v.length(); i++) n += v[i].b*deg(v[i].a); zz_pX g(INIT_SIZE, n+1); set(g); for (i = 0; i < v.length(); i++) for (j = 0; j < v[i].b; j++) { mul(g, g, v[i].a); } f = g; } static long BaseCase(const zz_pX& h, long q, long a, const zz_pXModulus& F) { long b, e; zz_pX lh(INIT_SIZE, F.n); lh = h; b = 1; e = 0; while (e < a-1 && !IsX(lh)) { e++; b *= q; PowerCompose(lh, lh, q, F); } if (!IsX(lh)) b *= q; return b; } void TandemPowerCompose(zz_pX& y1, zz_pX& y2, const zz_pX& h, long q1, long q2, const zz_pXModulus& F) { zz_pX z(INIT_SIZE, F.n); long sw; z = h; SetX(y1); SetX(y2); while (q1 || q2) { sw = 0; if (q1 > 1 || q2 > 1) sw = 4; if (q1 & 1) { if (IsX(y1)) y1 = z; else sw = sw | 2; } if (q2 & 1) { if (IsX(y2)) y2 = z; else sw = sw | 1; } switch (sw) { case 0: break; case 1: CompMod(y2, y2, z, F); break; case 2: CompMod(y1, y1, z, F); break; case 3: Comp2Mod(y1, y2, y1, y2, z, F); break; case 4: CompMod(z, z, z, F); break; case 5: Comp2Mod(z, y2, z, y2, z, F); break; case 6: Comp2Mod(z, y1, z, y1, z, F); break; case 7: Comp3Mod(z, y1, y2, z, y1, y2, z, F); break; } q1 = q1 >> 1; q2 = q2 >> 1; } } long RecComputeDegree(long u, const zz_pX& h, const zz_pXModulus& F, FacVec& fvec) { if (IsX(h)) return 1; if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F); zz_pX h1, h2; long q1, q2, r1, r2; q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); r1 = RecComputeDegree(fvec[u].link, h2, F, fvec); r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec); return r1*r2; } long ComputeDegree(const zz_pX& h, const zz_pXModulus& F) // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed { if (F.n == 1 || IsX(h)) return 1; FacVec fvec; FactorInt(fvec, F.n); return RecComputeDegree(fvec.length()-1, h, F, fvec); } long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F) { if (F.n == 1 || IsX(h)) return 1; long n = F.n; zz_pX P1, P2, P3; random(P1, n); TraceMap(P2, P1, n, F, h); ProbMinPolyMod(P3, P2, F, n/2); long r = deg(P3); if (r <= 0 || n % r != 0) return 0; else return n/r; } void FindRoot(zz_p& root, const zz_pX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { zz_pXModulus F; zz_pX h, h1, f; zz_p r; long p1; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); p1 = zz_p::modulus() >> 1; h1 = 1; while (deg(f) > 1) { build(F, f); random(r); PowerXPlusAMod(h, r, p1, F); sub(h, h, h1); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); } static long power(long a, long e) { long i, res; res = 1; for (i = 1; i <= e; i++) res = res * a; return res; } static long IrredBaseCase(const zz_pX& h, long q, long a, const zz_pXModulus& F) { long e; zz_pX X, s, d; e = power(q, a-1); PowerCompose(s, h, e, F); SetX(X); sub(s, s, X); GCD(d, F.f, s); return IsOne(d); } static long RecIrredTest(long u, const zz_pX& h, const zz_pXModulus& F, const FacVec& fvec) { long q1, q2; zz_pX h1, h2; if (IsX(h)) return 0; if (fvec[u].link == -1) { return IrredBaseCase(h, fvec[u].q, fvec[u].a, F); } q1 = fvec[fvec[u].link].val; q2 = fvec[fvec[u].link+1].val; TandemPowerCompose(h1, h2, h, q1, q2, F); return RecIrredTest(fvec[u].link, h2, F, fvec) && RecIrredTest(fvec[u].link+1, h1, F, fvec); } long DetIrredTest(const zz_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pXModulus F; build(F, f); zz_pX h; PowerXMod(h, zz_p::modulus(), F); zz_pX s; PowerCompose(s, h, F.n, F); if (!IsX(s)) return 0; FacVec fvec; FactorInt(fvec, F.n); return RecIrredTest(fvec.length()-1, h, F, fvec); } long IterIrredTest(const zz_pX& f) { if (deg(f) <= 0) return 0; if (deg(f) == 1) return 1; zz_pXModulus F; build(F, f); zz_pX h; PowerXMod(h, zz_p::modulus(), F); long rootn = SqrRoot(deg(f)); long CompTableSize = 2*rootn; zz_pXNewArgument H; long UseModComp = 1; if (NumBits(zz_p::modulus()) < rootn/2) UseModComp = 0; if (UseModComp) build(H, h, F, CompTableSize); long i, d, limit, limit_sqr; zz_pX g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= deg(f)) { sub(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { if (UseModComp) CompMod(g, g, H, F); else PowerMod(g, g, zz_p::modulus(), F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; } static void MulByXPlusY(vec_zz_pX& h, const zz_pX& f, const zz_pX& g) // h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k, // where the h[i]'s are polynomials in X, each of degree < deg(f), // and k < deg(g). // h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)). { long n = deg(g); long k = h.length()-1; if (k < 0) return; if (k < n-1) { h.SetLength(k+2); h[k+1] = h[k]; for (long i = k; i >= 1; i--) { MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); } MulByXMod(h[0], h[0], f); } else { zz_pX b, t; b = h[n-1]; for (long i = n-1; i >= 1; i--) { mul(t, b, g.rep[i]); MulByXMod(h[i], h[i], f); add(h[i], h[i], h[i-1]); sub(h[i], h[i], t); } mul(t, b, g.rep[0]); MulByXMod(h[0], h[0], f); sub(h[0], h[0], t); } // normalize k = h.length()-1; while (k >= 0 && IsZero(h[k])) k--; h.SetLength(k+1); } static void IrredCombine(zz_pX& x, const zz_pX& f, const zz_pX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_zz_pX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_zz_p a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); } static void BuildPrimePowerIrred(zz_pX& f, long q, long e) { long n = power(q, e); do { random(f, n); SetCoeff(f, n); } while (!IterIrredTest(f)); } static void RecBuildIrred(zz_pX& f, long u, const FacVec& fvec) { if (fvec[u].link == -1) BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a); else { zz_pX g, h; RecBuildIrred(g, fvec[u].link, fvec); RecBuildIrred(h, fvec[u].link+1, fvec); IrredCombine(f, g, h); } } void BuildIrred(zz_pX& f, long n) { if (n <= 0) LogicError("BuildIrred: n must be positive"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in BuildIrred"); if (n == 1) { SetX(f); return; } FacVec fvec; FactorInt(fvec, n); RecBuildIrred(f, fvec.length()-1, fvec); } void BuildRandomIrred(zz_pX& f, const zz_pX& g) { zz_pXModulus G; zz_pX h, ff; build(G, g); do { random(h, deg(g)); IrredPolyMod(ff, h, G); } while (deg(ff) < deg(g)); f = ff; } /************* NEW DDF ****************/ NTL_CHEAP_THREAD_LOCAL long zz_pX_GCDTableSize = 4; static NTL_CHEAP_THREAD_LOCAL vec_zz_pX *BabyStepFile = 0; static NTL_CHEAP_THREAD_LOCAL vec_zz_pX *GiantStepFile = 0; static NTL_CHEAP_THREAD_LOCAL zz_pXNewArgument *HHH = 0; static NTL_CHEAP_THREAD_LOCAL long OldN = 0; static void GenerateBabySteps(zz_pX& h1, const zz_pX& f, const zz_pX& h, long k, long verbose) { double t; if (verbose) { cerr << "generating baby steps..."; t = GetTime(); } zz_pXModulus F; build(F, f); (*BabyStepFile).SetLength(k-1); h1 = h; long i; long rootn = SqrRoot(F.n); if (NumBits(zz_p::modulus()) < rootn/2) { for (i = 1; i <= k-1; i++) { (*BabyStepFile)(i) = h1; PowerMod(h1, h1, zz_p::modulus(), F); if (verbose) cerr << "+"; } } else { zz_pXNewArgument H; build(H, h, F, 2*rootn); for (i = 1; i <= k-1; i++) { (*BabyStepFile)(i) = h1; CompMod(h1, h1, H, F); if (verbose) cerr << "."; } } if (verbose) cerr << (GetTime()-t) << "\n"; } static void GenerateGiantSteps(const zz_pX& f, const zz_pX& h, long l, long verbose) { zz_pXModulus F; build(F, f); build(*HHH, h, F, 2*SqrRoot(F.n)); OldN = F.n; (*GiantStepFile).SetLength(1); (*GiantStepFile)(1) = h; } static void NewAddFactor(vec_pair_zz_pX_long& u, const zz_pX& g, long m, long verbose) { long len = u.length(); u.SetLength(len+1); u[len].a = g; u[len].b = m; if (verbose) { cerr << "split " << m << " " << deg(g) << "\n"; } } static void NewProcessTable(vec_pair_zz_pX_long& u, zz_pX& f, const zz_pXModulus& F, vec_zz_pX& buf, long size, long StartInterval, long IntervalLength, long verbose) { if (size == 0) return; zz_pX& g = buf[size-1]; long i; for (i = 0; i < size-1; i++) MulMod(g, g, buf[i], F); GCD(g, f, g); if (deg(g) == 0) return; div(f, f, g); long d = (StartInterval-1)*IntervalLength + 1; i = 0; long interval = StartInterval; while (i < size-1 && 2*d <= deg(g)) { GCD(buf[i], buf[i], g); if (deg(buf[i]) > 0) { NewAddFactor(u, buf[i], interval, verbose); div(g, g, buf[i]); } i++; interval++; d += IntervalLength; } if (deg(g) > 0) { if (i == size-1) NewAddFactor(u, g, interval, verbose); else NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose); } } static void FetchGiantStep(zz_pX& g, long gs, const zz_pXModulus& F) { long l = (*GiantStepFile).length(); zz_pX last; if (gs > l+1) LogicError("bad arg to FetchGiantStep"); if (gs == l+1) { last = (*GiantStepFile)(l); if (F.n < OldN) { rem(last, last, F); reduce(*HHH, F); OldN = F.n; } (*GiantStepFile).SetLength(l+1); CompMod((*GiantStepFile)(l+1), last, *HHH, F); g = (*GiantStepFile)(l+1); } else if (deg((*GiantStepFile)(gs)) >= F.n) rem(g, (*GiantStepFile)(gs), F); else g = (*GiantStepFile)(gs); } static void FetchBabySteps(vec_zz_pX& v, long k) { v.SetLength(k); SetX(v[0]); long i; for (i = 1; i <= k-1; i++) { v[i] = (*BabyStepFile)(i); } } static void GiantRefine(vec_pair_zz_pX_long& u, const zz_pX& ff, long k, long l, long verbose) { double t; if (verbose) { cerr << "giant refine..."; t = GetTime(); } u.SetLength(0); vec_zz_pX BabyStep; FetchBabySteps(BabyStep, k); vec_zz_pX buf(INIT_SIZE, zz_pX_GCDTableSize); zz_pX f; f = ff; zz_pXModulus F; build(F, f); zz_pX g; zz_pX h; long size = 0; long first_gs; long d = 1; while (2*d <= deg(f)) { long old_n = deg(f); long gs = (d+k-1)/k; long bs = gs*k - d; if (bs == k-1) { size++; if (size == 1) first_gs = gs; FetchGiantStep(g, gs, F); sub(buf[size-1], g, BabyStep[bs]); } else { sub(h, g, BabyStep[bs]); MulMod(buf[size-1], buf[size-1], h, F); } if (verbose && bs == 0) cerr << "+"; if (size == zz_pX_GCDTableSize && bs == 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; size = 0; } d++; if (2*d <= deg(f) && deg(f) < old_n) { build(F, f); long i; for (i = 1; i <= k-1; i++) rem(BabyStep[i], BabyStep[i], F); } } if (size > 0) { NewProcessTable(u, f, F, buf, size, first_gs, k, verbose); if (verbose) cerr << "*"; } if (deg(f) > 0) NewAddFactor(u, f, 0, verbose); if (verbose) { t = GetTime()-t; cerr << "giant refine time: " << t << "\n"; } } static void IntervalRefine(vec_pair_zz_pX_long& factors, const zz_pX& ff, long k, long gs, const vec_zz_pX& BabyStep, long verbose) { vec_zz_pX buf(INIT_SIZE, zz_pX_GCDTableSize); zz_pX f; f = ff; zz_pXModulus F; build(F, f); zz_pX g; FetchGiantStep(g, gs, F); long size = 0; long first_d; long d = (gs-1)*k + 1; long bs = k-1; while (bs >= 0 && 2*d <= deg(f)) { long old_n = deg(f); if (size == 0) first_d = d; rem(buf[size], BabyStep[bs], F); sub(buf[size], buf[size], g); size++; if (size == zz_pX_GCDTableSize) { NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); size = 0; } d++; bs--; if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) { build(F, f); rem(g, g, F); } } NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose); if (deg(f) > 0) NewAddFactor(factors, f, deg(f), verbose); } static void BabyRefine(vec_pair_zz_pX_long& factors, const vec_pair_zz_pX_long& u, long k, long l, long verbose) { double t; if (verbose) { cerr << "baby refine..."; t = GetTime(); } factors.SetLength(0); vec_zz_pX BabyStep; long i; for (i = 0; i < u.length(); i++) { const zz_pX& g = u[i].a; long gs = u[i].b; if (gs == 0 || 2*((gs-1)*k+1) > deg(g)) NewAddFactor(factors, g, deg(g), verbose); else { if (BabyStep.length() == 0) FetchBabySteps(BabyStep, k); IntervalRefine(factors, g, k, gs, BabyStep, verbose); } } if (verbose) { t = GetTime()-t; cerr << "baby refine time: " << t << "\n"; } } void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose) { if (!IsOne(LeadCoeff(f))) LogicError("NewDDF: bad args"); if (deg(f) == 0) { factors.SetLength(0); return; } if (deg(f) == 1) { factors.SetLength(0); append(factors, cons(f, 1L)); return; } long B = deg(f)/2; long k = SqrRoot(B); // we double the number of baby steps if it seems like // baby steps are significantly cheaper than giant steps. // The calculations below are closely tied to a test in GenerateBabySteps: // if nbm >= sdf/2, then scale should be 1 (baby steps and giant steps balanced) if (B >= 500) { long sdf = SqrRoot(deg(f)); long nbm = NumBits(zz_p::modulus()); double scale = 0.25*double(sdf)/double(nbm); if (scale < 1) scale = 1; if (scale > 2) scale = 2; k = long(scale*k); } long l = (B+k-1)/k; vec_zz_pX local_BabyStepFile; vec_zz_pX local_GiantStepFile; zz_pXNewArgument local_HHH; BabyStepFile = &local_BabyStepFile; GiantStepFile = &local_GiantStepFile; HHH = &local_HHH; zz_pX h1; GenerateBabySteps(h1, f, h, k, verbose); GenerateGiantSteps(f, h1, l, verbose); vec_pair_zz_pX_long u; GiantRefine(u, f, k, l, verbose); BabyRefine(factors, u, k, l, verbose); } NTL_END_IMPL ntl-11.5.1/src/mat_GF2.cpp0000644417616742025610000003151314064716022016672 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long mw = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { _ntl_ulong *xp = X[i].rep.elts(); const _ntl_ulong *ap = A[i].rep.elts(); const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < mw; j++) xp[j] = ap[j] ^ bp[j]; } } static void mul_aux(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) { x.put(i, A[i] * b); } } void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { if (&b == &x || A.alias(x)) { vec_GF2 tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); clear(x); const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; _ntl_ulong *xp = x.rep.elts(); long lw = (l + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) { const _ntl_ulong *bp = B[i].rep.elts(); long j; for (j = 0; j < lw; j++) xp[j] ^= bp[j]; } a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } } void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B) { if (&a == &x || B.alias(x)) { vec_GF2 tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void mul_aux(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); long i; for (i = 1; i <= n; i++) { mul_aux(X(i), A(i), B); } } void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { if (&X == &A || &X == &B) { mat_GF2 tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void ident(mat_GF2& X, long n) { X.SetDims(n, n); clear(X); long i; for (i = 0; i < n; i++) X.put(i, i, to_GF2(1)); } void determinant(ref_GF2 d, const mat_GF2& M_in) { long k, n; long i, j; long pos; n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } mat_GF2 M; M = M_in; long wn = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } set(d); return; } static long IsUnitVector(const vec_GF2& a, long i) { long wi = i/NTL_BITS_PER_LONG; long bi = i - wi*NTL_BITS_PER_LONG; const _ntl_ulong *p = a.rep.elts(); long wdlen = a.rep.length(); long j; for (j = 0; j < wi; j++) if (p[j] != 0) return 0; if (p[wi] != (1UL << bi)) return 0; for (j = wi+1; j < wdlen; j++) if (p[j] != 0) return 0; return 1; } long IsIdent(const mat_GF2& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (n == 0) return 1; long i; for (i = 0; i < n; i++) if (!IsUnitVector(A[i], i)) return 0; return 1; } void AddToCol(mat_GF2& x, long j, const vec_GF2& a) // add a to column j of x // ALIAS RESTRICTION: a should not alias any row of x { long n = x.NumRows(); long m = x.NumCols(); if (a.length() != n || j < 0 || j >= m) LogicError("AddToCol: bad args"); long wj = j/NTL_BITS_PER_LONG; long bj = j - wj*NTL_BITS_PER_LONG; _ntl_ulong j_mask = 1UL << bj; const _ntl_ulong *ap = a.rep.elts(); _ntl_ulong a_mask = 1; long i; for (i = 0; i < n; i++) { if (*ap & a_mask) x[i].rep.elts()[wj] ^= j_mask; a_mask <<= 1; if (!a_mask) { a_mask = 1; ap++; } } } void transpose_aux(mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(m, n); clear(X); long i; for (i = 0; i < n; i++) AddToCol(X, i, A[i]); } void transpose(mat_GF2& X, const mat_GF2& A) { if (&X == &A) { mat_GF2 tmp; transpose_aux(tmp, A); X = tmp; } else transpose_aux(X, A); } static void solve_impl(ref_GF2 d, vec_GF2& X, const mat_GF2& A, const vec_GF2& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { X.SetLength(0); set(d); return; } long i, j, k, pos; mat_GF2 M; M.SetDims(n, n+1); if (trans) { for (i = 0; i < n; i++) { AddToCol(M, i, A[i]); } } else { for (i = 0; i < n; i++) { VectorCopy(M[i], A[i], n+1); } } AddToCol(M, n, b); long wn = ((n+1) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(n+1); XX.put(n, 1); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); X = XX; set(d); return; } void solve(ref_GF2 d, vec_GF2& x, const mat_GF2& A, const vec_GF2& b) { solve_impl(d, x, A, b, true); } void solve(ref_GF2 d, const mat_GF2& A, vec_GF2& x, const vec_GF2& b) { solve_impl(d, x, A, b, false); } void inv(ref_GF2 d, mat_GF2& X, const mat_GF2& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (n == 0) { X.SetDims(0, 0); set(d); } long i, j, k, pos; mat_GF2 M; M.SetDims(n, 2*n); vec_GF2 aa; aa.SetLength(2*n); for (i = 0; i < n; i++) { aa = A[i]; aa.SetLength(2*n); aa.put(n+i, 1); M[i] = aa; } long wn = ((2*n) + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; for (k = 0; k < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = k; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); } _ntl_ulong *y = M[k].rep.elts(); for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wn; j++) x[j] ^= y[j]; } } } else { clear(d); return; } } vec_GF2 XX; XX.SetLength(2*n); X.SetDims(n, n); clear(X); for (j = 0; j < n; j++) { XX.SetLength(n+j+1); clear(XX); XX.put(n+j, to_GF2(1)); for (i = n-1; i >= 0; i--) { XX.put(i, XX*M[i]); } XX.SetLength(n); AddToCol(X, j, XX); } set(d); return; } long gauss(mat_GF2& M, long w) { long k, l; long i, j; long pos; long n = M.NumRows(); long m = M.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); long wm = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; l = 0; for (k = 0; k < w && l < n; k++) { long wk = k/NTL_BITS_PER_LONG; long bk = k - wk*NTL_BITS_PER_LONG; _ntl_ulong k_mask = 1UL << bk; pos = -1; for (i = l; i < n; i++) { if (M[i].rep.elts()[wk] & k_mask) { pos = i; break; } } if (pos != -1) { if (l != pos) swap(M[pos], M[l]); _ntl_ulong *y = M[l].rep.elts(); for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] if (M[i].rep.elts()[wk] & k_mask) { _ntl_ulong *x = M[i].rep.elts(); for (j = wk; j < wm; j++) x[j] ^= y[j]; } } l++; } } return l; } long gauss(mat_GF2& M) { return gauss(M, M.NumCols()); } void image(mat_GF2& X, const mat_GF2& A) { mat_GF2 M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_GF2& X, const mat_GF2& A) { long m = A.NumRows(); long n = A.NumCols(); mat_GF2 M; long r; transpose(M, A); r = gauss(M); X.SetDims(m-r, m); clear(X); long i, j, k; vec_long D; D.SetLength(m); for (j = 0; j < m; j++) D[j] = -1; j = -1; for (i = 0; i < r; i++) { do { j++; } while (M.get(i, j) == 0); D[j] = i; } for (k = 0; k < m-r; k++) { vec_GF2& v = X[k]; long pos = 0; for (j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) { v[j] = 1; // v.put(j, to_GF2(1)); } pos++; } else { v[j] = v*M[D[j]]; // v.put(j, v*M[D[j]]); } } } } void mul(mat_GF2& X, const mat_GF2& A, GF2 b) { X = A; if (b == 0) clear(X); } void diag(mat_GF2& X, long n, GF2 d) { if (d == 1) ident(X, n); else { X.SetDims(n, n); clear(X); } } long IsDiag(const mat_GF2& A, long n, GF2 d) { if (A.NumRows() != n || A.NumCols() != n) return 0; if (d == 1) return IsIdent(A, n); else return IsZero(A); } long IsZero(const mat_GF2& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_GF2& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; add(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b) { mat_GF2 res; add(res, a, b); NTL_OPT_RETURN(mat_GF2, res); } vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b) { vec_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b) { vec_GF2 res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } void inv(mat_GF2& X, const mat_GF2& A) { GF2 d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_GF2& X, const mat_GF2& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_GF2 T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } void random(mat_GF2& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_GF2E.cpp0000644417616742025610000004433314064716022017003 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_START_IMPL //=========================================================== #define PAR_THRESH (40000.0) static double GF2E_SizeInWords() { return GF2E::WordLength(); } static void mul_aux(Mat& X, const Mat& A, const Mat& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); GF2Context GF2_context; GF2_context.save(); GF2EContext GF2E_context; GF2E_context.save(); double sz = GF2E_SizeInWords(); bool seq = (double(n)*double(l)*double(m)*sz*sz < PAR_THRESH); NTL_GEXEC_RANGE(seq, m, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) GF2_context.restore(); GF2E_context.restore(); long i, j, k; GF2X acc, tmp; Vec B_col; B_col.SetLength(l); for (j = first; j < last; j++) { for (k = 0; k < l; k++) B_col[k] = B[k][j]; for (i = 0; i < n; i++) { clear(acc); for (k = 0; k < l; k++) { mul(tmp, rep(A[i][k]), rep(B_col[k])); add(acc, acc, tmp); } conv(X[i][j], acc); } } NTL_GEXEC_RANGE_END } void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { if (&X == &A || &X == &B) { mat_GF2E tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void inv(GF2E& d, Mat& X, const Mat& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } const GF2XModulus& G = GF2E::modulus(); GF2X t1, t2; GF2X pivot; GF2X pivot_inv; Vec< GF2XVec > M; // scratch space M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n, 2*GF2E::WordLength()); for (long j = 0; j < n; j++) { M[i][j] = rep(A[i][j]); } } GF2X det; det = 1; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations GF2Context GF2_context; GF2_context.save(); double sz = GF2E_SizeInWords(); bool seq = double(n)*double(n)*sz*sz < PAR_THRESH; bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(pivot, M[i][k], G); if (pivot != 0) { InvMod(pivot_inv, pivot, G); pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); P[k] = pos; pivoting = true; } MulMod(det, det, pivot, G); { // multiply row k by pivot_inv GF2X *y = &M[k][0]; for (long j = 0; j < n; j++) { rem(t2, y[j], G); MulMod(y[j], t2, pivot_inv, G); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(k) GF2_context.restore(); GF2X *y = &M[k][0]; GF2X t1, t2; for (long i = first; i < last; i++) { if (i == k) continue; // skip row k GF2X *x = &M[i][0]; rem(t1, x[k], G); negate(t1, t1); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i for (long j = 0; j < n; j++) { mul(t2, y[j], t1); add(x[j], x[j], t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { GF2X *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) conv(X[i][j], M[i][j]); conv(d, det); } static void solve_impl(GF2E& d, Vec& X, const Mat& A, const Vec& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } GF2X t1, t2; const GF2XModulus& G = GF2E::modulus(); Vec< GF2XVec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n+1, 2*GF2E::WordLength()); if (trans) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); else for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); M[i][n] = rep(b[i]); } GF2X det; set(det); GF2Context GF2_context; GF2_context.save(); double sz = GF2E_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j <= n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) GF2_context.restore(); GF2X t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced GF2X *x = M[i].elts() + (k+1); GF2X *y = M[k].elts() + (k+1); for (long j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } X.SetLength(n); for (long i = n-1; i >= 0; i--) { clear(t1); for (long j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void solve(GF2E& d, Vec& x, const Mat& A, const Vec& b) { solve_impl(d, x, A, b, true); } void solve(GF2E& d, const Mat& A, Vec& x, const Vec& b) { solve_impl(d, x, A, b, false); } long gauss(Mat& M_in, long w) { GF2X t1, t2; GF2X piv; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); const GF2XModulus& G = GF2E::modulus(); Vec< GF2XVec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(m, 2*GF2E::WordLength()); for (long j = 0; j < m; j++) { M[i][j] = rep(M_in[i][j]); } } GF2Context GF2_context; GF2_context.save(); double sz = GF2E_SizeInWords(); long l = 0; for (long k = 0; k < w && l < n; k++) { long pos = -1; for (long i = l; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(piv, M[l][k], G); negate(piv, piv); for (long j = k+1; j < m; j++) { rem(M[l][j], M[l][j], G); } bool seq = double(n-(l+1))*double(m-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(l+1), first, last) NTL_IMPORT(m) NTL_IMPORT(k) NTL_IMPORT(l) GF2_context.restore(); GF2X t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + l+1; // M[i] = M[i] + M[l]*M[i,k]*piv MulMod(t1, M[i][k], piv, G); clear(M[i][k]); GF2X *x = M[i].elts() + (k+1); GF2X *y = M[l].elts() + (k+1); for (long j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } NTL_GEXEC_RANGE_END l++; } } for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(Mat& M) { return gauss(M, M.NumCols()); } void image(Mat& X, const Mat& A) { Mat M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(Mat& X, const Mat& A) { long m = A.NumRows(); long n = A.NumCols(); const GF2XModulus& G = GF2E::modulus(); Mat M; transpose(M, A); long r = gauss(M); if (r == 0) { ident(X, m); return; } X.SetDims(m-r, m); if (m-r == 0 || m == 0) return; Vec D; D.SetLength(m); for (long j = 0; j < m; j++) D[j] = -1; Vec inverses; inverses.SetLength(m); for (long i = 0, j = -1; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } GF2EContext GF2E_context; GF2E_context.save(); GF2Context GF2_context; GF2_context.save(); double sz = GF2E_SizeInWords(); bool seq = double(m-r)*double(r)*double(r)*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, m-r, first, last) NTL_IMPORT(m) NTL_IMPORT(r) GF2_context.restore(); GF2E_context.restore(); GF2X t1, t2; GF2E T3; for (long k = first; k < last; k++) { Vec& v = X[k]; long pos = 0; for (long j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { long i = D[j]; clear(t1); for (long s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } NTL_GEXEC_RANGE_END } void determinant(GF2E& d, const Mat& M_in) { GF2X t1, t2; const GF2XModulus& G = GF2E::modulus(); long n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } Vec< GF2XVec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n, 2*GF2E::WordLength()); for (long j = 0; j < n; j++) { M[i][j] = rep(M_in[i][j]); } } GF2X det; set(det); GF2Context GF2_context; GF2_context.save(); double sz = GF2E_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j < n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) GF2_context.restore(); GF2X t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced GF2X *x = M[i].elts() + (k+1); GF2X *y = M[k].elts() + (k+1); for (long j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } conv(d, det); } //=========================================================== void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } static void mul_aux(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; GF2X acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b) { if (&b == &x || A.alias(x)) { vec_GF2E tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; GF2X acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B) { if (&a == &x) { vec_GF2E tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_GF2E& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } long IsIdent(const mat_GF2E& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_GF2E& X, const mat_GF2E& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_GF2E tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b_in) { GF2E b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b) { X = A; if (b == 0) clear(X); } void diag(mat_GF2E& X, long n, const GF2E& d_in) { GF2E d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_GF2E& A, long n, const GF2E& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_GF2E& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_GF2E& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; add(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b) { mat_GF2E res; sub(res, a, b); NTL_OPT_RETURN(mat_GF2E, res); } mat_GF2E operator-(const mat_GF2E& a) { mat_GF2E res; negate(res, a); NTL_OPT_RETURN(mat_GF2E, res); } vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b) { vec_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b) { vec_GF2E res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } void inv(mat_GF2E& X, const mat_GF2E& A) { GF2E d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_GF2E T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } void random(mat_GF2E& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_RR.cpp0000644417616742025610000002737314064716022016650 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void add(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void mul_aux(mat_RR& X, const mat_RR& A, const mat_RR& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; RR acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, A(i,k), B(k,j)); add(acc, acc, tmp); } X(i,j) = acc; } } } void mul(mat_RR& X, const mat_RR& A, const mat_RR& B) { if (&X == &A || &X == &B) { mat_RR tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_RR& x, const mat_RR& A, const vec_RR& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; RR acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, A(i,k), b(k)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_RR& x, const mat_RR& A, const vec_RR& b) { if (&b == &x || A.alias(x)) { vec_RR tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_RR& x, const vec_RR& a, const mat_RR& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; RR acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, a(k), B(k,i)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_RR& x, const vec_RR& a, const mat_RR& B) { if (&a == &x) { vec_RR tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_RR& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(RR& d, const mat_RR& M_in) { long k, n; long i, j; long pos; RR t1, t2; RR *x, *y; n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } mat_RR M; M = M_in; RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j < n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } d = det; } RR determinant(const mat_RR& a) { RR x; determinant(x, a); NTL_OPT_RETURN(RR, x); } long IsIdent(const mat_RR& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_RR& X, const mat_RR& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_RR tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; RR t1, t2; RR *x, *y; mat_RR M; M.SetDims(n, n+1); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) M[i][j] = A[j][i]; M[i][n] = b[i]; } RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j <= n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j], M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); X[i] = t1; } d = det; } void inv(RR& d, mat_RR& X, const mat_RR& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; RR t1, t2; RR *x, *y; mat_RR M; M.SetDims(n, 2*n); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { M[i][j] = A[i][j]; clear(M[i][n+j]); } set(M[i][n+i]); } RR det; set(det); RR maxval; for (k = 0; k < n; k++) { pos = -1; clear(maxval); for (i = k; i < n; i++) { abs(t1, M[i][k]); if (t1 > maxval) { pos = i; maxval = t1; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } mul(det, det, M[k][k]); // make M[k, k] == -1 inv(t1, M[k][k]); negate(t1, t1); for (j = k+1; j < 2*n; j++) { mul(M[k][j], M[k][j], t1); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, X[j][k], M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); X[i][k] = t1; } } d = det; } void mul(mat_RR& X, const mat_RR& A, const RR& b_in) { RR b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_RR& X, const mat_RR& A, double b_in) { RR b; b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_RR& X, long n, const RR& d_in) { RR d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_RR& A, long n, const RR& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void negate(mat_RR& X, const mat_RR& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } long IsZero(const mat_RR& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_RR& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_RR operator+(const mat_RR& a, const mat_RR& b) { mat_RR res; add(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator*(const mat_RR& a, const mat_RR& b) { mat_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator-(const mat_RR& a, const mat_RR& b) { mat_RR res; sub(res, a, b); NTL_OPT_RETURN(mat_RR, res); } mat_RR operator-(const mat_RR& a) { mat_RR res; negate(res, a); NTL_OPT_RETURN(mat_RR, res); } vec_RR operator*(const mat_RR& a, const vec_RR& b) { vec_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator*(const vec_RR& a, const mat_RR& b) { vec_RR res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_RR, res); } void inv(mat_RR& X, const mat_RR& A) { RR d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_RR& X, const mat_RR& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_RR T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } NTL_END_IMPL ntl-11.5.1/src/mat_ZZ.cpp0000644417616742025610000005700614064716022016664 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void mul_aux(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); long i, j, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { clear(acc); for(k = 1; k <= l; k++) { mul(tmp, A(i,k), B(k,j)); add(acc, acc, tmp); } X(i,j) = acc; } } } void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B) { if (&X == &A || &X == &B) { mat_ZZ tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } static void mul_aux(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, A(i,k), b(k)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b) { if (&b == &x || A.alias(x)) { vec_ZZ tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, a(k), B(k,i)); add(acc, acc, tmp); } x(i) = acc; } } void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B) { if (&a == &x) { vec_ZZ tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } static long DetBound(const mat_ZZ& a) { long n = a.NumRows(); long i; ZZ res, t1; set(res); for (i = 0; i < n; i++) { InnerProduct(t1, a[i], a[i]); if (t1 > 1) { SqrRoot(t1, t1); add(t1, t1, 1); } mul(res, res, t1); } return NumBits(res); } void determinant(ZZ& rres, const mat_ZZ& a, long deterministic) { long n = a.NumRows(); if (a.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(rres); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); long instable = 1; long gp_cnt = 0; long bound = 2+DetBound(a); ZZ res, prod; clear(res); set(prod); long i; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(res))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p A; conv(A, a); ZZ_p t; determinant(t, A); if (CRT(res, prod, rep(t), P)) instable = 1; else break; } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p A; conv(A, a); zz_p t; determinant(t, A); instable = CRT(res, prod, rep(t), p); } rres = res; zbak.restore(); Zbak.restore(); } void conv(mat_zz_p& x, const mat_ZZ& a) { long n = a.NumRows(); long m = a.NumCols(); long i; x.SetDims(n, m); for (i = 0; i < n; i++) conv(x[i], a[i]); } void conv(mat_ZZ_p& x, const mat_ZZ& a) { long n = a.NumRows(); long m = a.NumCols(); long i; x.SetDims(n, m); for (i = 0; i < n; i++) conv(x[i], a[i]); } long IsIdent(const mat_ZZ& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ& X, const mat_ZZ& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } long CRT(mat_ZZ& gg, ZZ& a, const mat_zz_p& G) { long n = gg.NumRows(); long m = gg.NumCols(); if (G.NumRows() != n || G.NumCols() != m) LogicError("CRT: dimension mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i, j; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { if (!CRTInRange(gg[i][j], a)) { modified = 1; rem(g, gg[i][j], a); if (g > a1) sub(g, g, a); } else g = gg[i][j]; h = rem(g, p); h = SubMod(rep(G[i][j]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i][j] = g; } } a = new_a; return modified; } void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b_in) { ZZ b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ& X, const mat_ZZ& A, long b) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } static void ExactDiv(vec_ZZ& x, const ZZ& d) { long n = x.length(); long i; for (i = 0; i < n; i++) if (!divide(x[i], x[i], d)) ArithmeticError("inexact division"); } static void ExactDiv(mat_ZZ& x, const ZZ& d) { long n = x.NumRows(); long m = x.NumCols(); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) if (!divide(x[i][j], x[i][j], d)) ArithmeticError("inexact division"); } void diag(mat_ZZ& X, long n, const ZZ& d_in) { ZZ d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ& A, long n, const ZZ& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void solve(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); vec_ZZ x(INIT_SIZE, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long check = 0; long gp_cnt = 0; vec_ZZ y, b1; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { vec_zz_p bb, xx; conv(bb, b); zz_p dd; solve(dd, xx, AA, bb); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); mul(b1, b, d); if (y == b1) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); } void inv(ZZ& d_out, mat_ZZ& x_out, const mat_ZZ& A, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (n == 0) { set(d_out); x_out.SetDims(0, 0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); mat_ZZ x(INIT_SIZE, n, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long gp_cnt = 0; long check = 0; mat_ZZ y; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { mat_zz_p xx; zz_p dd; inv(dd, xx, AA); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); if (IsDiag(y, n, d)) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); } void negate(mat_ZZ& X, const mat_ZZ& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } long IsZero(const mat_ZZ& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b) { mat_ZZ res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ, res); } mat_ZZ operator-(const mat_ZZ& a) { mat_ZZ res; negate(res, a); NTL_OPT_RETURN(mat_ZZ, res); } vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b) { vec_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b) { vec_ZZ res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } void inv(mat_ZZ& X, const mat_ZZ& A) { ZZ d; inv(d, X, A); if (d == -1) negate(X, X); else if (d != 1) ArithmeticError("inv: non-invertible matrix"); } void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } /*********************************************************** routines for solving a linear system via Hensel lifting ************************************************************/ static long MaxBits(const mat_ZZ& A) { long m = 0; long i, j; for (i = 0; i < A.NumRows(); i++) for (j = 0; j < A.NumCols(); j++) m = max(m, NumBits(A[i][j])); return m; } // Computes an upper bound on the numerators and denominators // to the solution x*A = b using Hadamard's bound and Cramer's rule. // If A contains a zero row, then sets both bounds to zero. static void hadamard(ZZ& num_bound, ZZ& den_bound, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); if (n == 0) LogicError("internal error: hadamard with n = 0"); ZZ b_len, min_A_len, prod, t1; InnerProduct(min_A_len, A[0], A[0]); prod = min_A_len; long i; for (i = 1; i < n; i++) { InnerProduct(t1, A[i], A[i]); if (t1 < min_A_len) min_A_len = t1; mul(prod, prod, t1); } if (min_A_len == 0) { num_bound = 0; den_bound = 0; return; } InnerProduct(b_len, b, b); div(t1, prod, min_A_len); mul(t1, t1, b_len); SqrRoot(num_bound, t1); SqrRoot(den_bound, prod); } static void MixedMul(vec_ZZ& x, const vec_zz_p& a, const mat_ZZ& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, B(k, i), rep(a(k))); add(acc, acc, tmp); } x(i) = acc; } } static void SubDiv(vec_ZZ& e, const vec_ZZ& t, long p) { long n = e.length(); if (t.length() != n) LogicError("SubDiv: dimension mismatch"); ZZ s; long i; for (i = 0; i < n; i++) { sub(s, e[i], t[i]); div(e[i], s, p); } } static void MulAdd(vec_ZZ& x, const ZZ& prod, const vec_zz_p& h) { long n = x.length(); if (h.length() != n) LogicError("MulAdd: dimension mismatch"); ZZ t; long i; for (i = 0; i < n; i++) { mul(t, prod, rep(h[i])); add(x[i], x[i], t); } } static void double_MixedMul1(vec_ZZ& x, double *a, double **B, long n) { long i, k; double acc; for (i = 0; i < n; i++) { double *bp = B[i]; acc = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; } conv(x[i], acc); } } static void double_MixedMul2(vec_ZZ& x, double *a, double **B, long n, long limit) { long i, k; double acc; ZZ acc1, t; long j; for (i = 0; i < n; i++) { double *bp = B[i]; clear(acc1); acc = 0; j = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; j++; if (j == limit) { conv(t, acc); add(acc1, acc1, t); acc = 0; j = 0; } } if (j > 0) { conv(t, acc); add(acc1, acc1, t); } x[i] = acc1; } } static void long_MixedMul1(vec_ZZ& x, long *a, long **B, long n) { long i, k; long acc; for (i = 0; i < n; i++) { long *bp = B[i]; acc = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; } conv(x[i], acc); } } static void long_MixedMul2(vec_ZZ& x, long *a, long **B, long n, long limit) { long i, k; long acc; ZZ acc1, t; long j; for (i = 0; i < n; i++) { long *bp = B[i]; clear(acc1); acc = 0; j = 0; for (k = 0; k < n; k++) { acc += bp[k] * a[k]; j++; if (j == limit) { conv(t, acc); add(acc1, acc1, t); acc = 0; j = 0; } } if (j > 0) { conv(t, acc); add(acc1, acc1, t); } x[i] = acc1; } } void solve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve1: nonsquare matrix"); if (b.length() != n) LogicError("solve1: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } ZZ num_bound, den_bound; hadamard(num_bound, den_bound, A, b); if (den_bound == 0) { clear(d_out); return; } zz_pBak zbak; zbak.save(); long i; long j; ZZ prod; prod = 1; mat_zz_p B; for (i = 0; ; i++) { zz_p::FFTInit(i); mat_zz_p AA, BB; zz_p dd; conv(AA, A); inv(dd, BB, AA); if (dd != 0) { transpose(B, BB); break; } mul(prod, prod, zz_p::modulus()); if (prod > den_bound) { d_out = 0; return; } } long max_A_len = MaxBits(A); long use_double_mul1 = 0; long use_double_mul2 = 0; long double_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_DOUBLE_PRECISION-1) use_double_mul1 = 1; if (!use_double_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_DOUBLE_PRECISION-1) { use_double_mul2 = 1; double_limit = (1L << (NTL_DOUBLE_PRECISION-1-max_A_len-NTL_SP_NBITS)); } long use_long_mul1 = 0; long use_long_mul2 = 0; long long_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_BITS_PER_LONG-1) use_long_mul1 = 1; if (!use_long_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_BITS_PER_LONG-1) { use_long_mul2 = 1; long_limit = (1L << (NTL_BITS_PER_LONG-1-max_A_len-NTL_SP_NBITS)); } if (use_double_mul1 && use_long_mul1) use_long_mul1 = 0; else if (use_double_mul1 && use_long_mul2) use_long_mul2 = 0; else if (use_double_mul2 && use_long_mul1) use_double_mul2 = 0; else if (use_double_mul2 && use_long_mul2) { if (long_limit > double_limit) use_double_mul2 = 0; else use_long_mul2 = 0; } double **double_A=0; double *double_h=0; Unique2DArray double_A_store; UniqueArray double_h_store; if (use_double_mul1 || use_double_mul2) { double_h_store.SetLength(n); double_h = double_h_store.get(); double_A_store.SetDims(n, n); double_A = double_A_store.get(); for (i = 0; i < n; i++) for (j = 0; j < n; j++) double_A[j][i] = to_double(A[i][j]); } long **long_A=0; long *long_h=0; Unique2DArray long_A_store; UniqueArray long_h_store; if (use_long_mul1 || use_long_mul2) { long_h_store.SetLength(n); long_h = long_h_store.get(); long_A_store.SetDims(n, n); long_A = long_A_store.get(); for (i = 0; i < n; i++) for (j = 0; j < n; j++) long_A[j][i] = to_long(A[i][j]); } vec_ZZ x; x.SetLength(n); vec_zz_p h; h.SetLength(n); vec_ZZ e; e = b; vec_zz_p ee; vec_ZZ t; t.SetLength(n); prod = 1; ZZ bound1; mul(bound1, num_bound, den_bound); mul(bound1, bound1, 2); while (prod <= bound1) { conv(ee, e); mul(h, B, ee); if (use_double_mul1) { for (i = 0; i < n; i++) double_h[i] = to_double(rep(h[i])); double_MixedMul1(t, double_h, double_A, n); } else if (use_double_mul2) { for (i = 0; i < n; i++) double_h[i] = to_double(rep(h[i])); double_MixedMul2(t, double_h, double_A, n, double_limit); } else if (use_long_mul1) { for (i = 0; i < n; i++) long_h[i] = to_long(rep(h[i])); long_MixedMul1(t, long_h, long_A, n); } else if (use_long_mul2) { for (i = 0; i < n; i++) long_h[i] = to_long(rep(h[i])); long_MixedMul2(t, long_h, long_A, n, long_limit); } else MixedMul(t, h, A); // t = h*A SubDiv(e, t, zz_p::modulus()); // e = (e-t)/p MulAdd(x, prod, h); // x = x + prod*h mul(prod, prod, zz_p::modulus()); } vec_ZZ num, denom; ZZ d, d_mod_prod, tmp1; num.SetLength(n); denom.SetLength(n); d = 1; d_mod_prod = 1; for (i = 0; i < n; i++) { rem(x[i], x[i], prod); MulMod(x[i], x[i], d_mod_prod, prod); if (!ReconstructRational(num[i], denom[i], x[i], prod, num_bound, den_bound)) LogicError("solve1 internal error: rat recon failed!"); mul(d, d, denom[i]); if (i != n-1) { if (denom[i] != 1) { div(den_bound, den_bound, denom[i]); mul(bound1, num_bound, den_bound); mul(bound1, bound1, 2); div(tmp1, prod, zz_p::modulus()); while (tmp1 > bound1) { prod = tmp1; div(tmp1, prod, zz_p::modulus()); } rem(tmp1, denom[i], prod); rem(d_mod_prod, d_mod_prod, prod); MulMod(d_mod_prod, d_mod_prod, tmp1, prod); } } } tmp1 = 1; for (i = n-1; i >= 0; i--) { mul(num[i], num[i], tmp1); mul(tmp1, tmp1, denom[i]); } x_out.SetLength(n); for (i = 0; i < n; i++) { x_out[i] = num[i]; } d_out = d; } NTL_END_IMPL ntl-11.5.1/src/mat_ZZ_p.cpp0000644417616742025610000007365314064716022017211 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include // FIXME: only needed if we use multi-modular MM #include #include NTL_START_IMPL // ******************** Matrix Multiplication ************************ #ifdef NTL_HAVE_LL_TYPE #define NTL_USE_MM_MATMUL (1) #else #define NTL_USE_MM_MATMUL (0) #endif #define PAR_THRESH (40000.0) // *********************** Plain Matrix Multiplication *************** void plain_mul_aux(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); ZZ_pContext context; context.save(); long sz = ZZ_p::ModulusSize(); bool seq = (double(n)*double(l)*double(m)*double(sz)*double(sz) < PAR_THRESH); NTL_GEXEC_RANGE(seq, m, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) context.restore(); long i, j, k; ZZ acc, tmp; vec_ZZ_p B_col; B_col.SetLength(l); for (j = first; j < last; j++) { for (k = 0; k < l; k++) B_col[k] = B[k][j]; for (i = 0; i < n; i++) { clear(acc); for (k = 0; k < l; k++) { mul(tmp, rep(A[i][k]), rep(B_col[k])); add(acc, acc, tmp); } conv(X[i][j], acc); } } NTL_GEXEC_RANGE_END } void plain_mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { if (&X == &A || &X == &B) { mat_ZZ_p tmp; plain_mul_aux(tmp, A, B); X = tmp; } else plain_mul_aux(X, A, B); } // X = A*transpose(B) void plain_mul_transpose_aux(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumRows(); if (l != B.NumCols()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); ZZ_pContext context; context.save(); long sz = ZZ_p::ModulusSize(); bool seq = (double(n)*double(l)*double(m)*double(sz)*double(sz) < PAR_THRESH); NTL_GEXEC_RANGE(seq, m, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) context.restore(); long i, j, k; ZZ acc, tmp; for (j = first; j < last; j++) { const ZZ_p *B_col = B[j].elts(); for (i = 0; i < n; i++) { clear(acc); for (k = 0; k < l; k++) { mul(tmp, rep(A[i][k]), rep(B_col[k])); add(acc, acc, tmp); } conv(X[i][j], acc); } } NTL_GEXEC_RANGE_END } void plain_mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { if (&X == &A || &X == &B) { mat_ZZ_p tmp; plain_mul_transpose_aux(tmp, A, B); X = tmp; } else plain_mul_transpose_aux(X, A, B); } // ***************** Multi-modular Matrix Multiplication ************* struct mat_ZZ_p_crt_rep { Vec< Mat > rep; }; static const MatPrime_crt_helper& get_MatPrime_crt_helper_info() { do { Lazy::Builder builder(ZZ_pInfo->MatPrime_crt_helper_info); if (!builder()) break; UniquePtr p; p.make(); build(*p, ZZ_pInfo->p); builder.move(p); } while (0); return *ZZ_pInfo->MatPrime_crt_helper_info; } static void RawConvert(Mat& X, const Mat& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); for (long i = 0; i < n; i++) { const MatPrime_residue_t *Ai = A[i].elts(); zz_p *Xi = X[i].elts(); for (long j = 0; j < m; j++) Xi[j].LoopHole() = Ai[j]; } } static void RawConvertTranspose(Mat& X, const Mat& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(m, n); for (long i = 0; i < n; i++) { const MatPrime_residue_t *Ai = A[i].elts(); for (long j = 0; j < m; j++) X[j][i] = Ai[j]; } } static void RawConvert(Mat& X, const Mat& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); for (long i = 0; i < n; i++) { const zz_p *Ai = A[i].elts(); MatPrime_residue_t *Xi = X[i].elts(); for (long j = 0; j < m; j++) Xi[j] = rep(Ai[j]); } } #define CRT_BLK (8) void to_mat_ZZ_p_crt_rep(mat_ZZ_p_crt_rep& X, const mat_ZZ_p& A) { long n = A.NumRows(); long m = A.NumCols(); const MatPrime_crt_helper& H = get_MatPrime_crt_helper_info(); long nprimes = H.GetNumPrimes(); if (NTL_OVERFLOW(nprimes, CRT_BLK, 0)) ResourceError("overflow"); // this is pretty academic X.rep.SetLength(nprimes); for (long k = 0; k < nprimes; k++) X.rep[k].SetDims(n, m); ZZ_pContext context; context.save(); bool seq = (double(n)*double(m)*H.GetCost() < PAR_THRESH); // FIXME: right now, we just partition the rows, but if // #cols > #rows, we should perhaps partition the cols NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(m) NTL_IMPORT(nprimes) context.restore(); MatPrime_crt_helper_scratch scratch; Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); MatPrime_residue_t *remainders = remainders_store.elts(); for (long i = first; i < last; i++) { const ZZ_p *a = A[i].elts(); long jj = 0; for (; jj <= m-CRT_BLK; jj += CRT_BLK) { for (long j = 0; j < CRT_BLK; j++) reduce(H, rep(a[jj+j]), remainders + j*nprimes, scratch); for (long k = 0; k < nprimes; k++) { MatPrime_residue_t *x = X.rep[k][i].elts(); for (long j = 0; j < CRT_BLK; j++) x[jj+j] = remainders[j*nprimes+k]; } } if (jj < m) { for (long j = 0; j < m-jj; j++) reduce(H, rep(a[jj+j]), remainders + j*nprimes, scratch); for (long k = 0; k < nprimes; k++) { MatPrime_residue_t *x = X.rep[k][i].elts(); for (long j = 0; j < m-jj; j++) x[jj+j] = remainders[j*nprimes+k]; } } } NTL_GEXEC_RANGE_END } void from_mat_ZZ_p_crt_rep(const mat_ZZ_p_crt_rep& X, mat_ZZ_p& A) { long n = X.rep[0].NumRows(); long m = X.rep[0].NumCols(); const MatPrime_crt_helper& H = get_MatPrime_crt_helper_info(); long nprimes = H.GetNumPrimes(); if (NTL_OVERFLOW(nprimes, CRT_BLK, 0)) ResourceError("overflow"); // this is pretty academic A.SetDims(n, m); ZZ_pContext context; context.save(); bool seq = (double(n)*double(m)*H.GetCost() < PAR_THRESH); // FIXME: right now, we just partition the rows, but if // #cols > #rows, we should perhaps partition the cols NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(m) NTL_IMPORT(nprimes) context.restore(); MatPrime_crt_helper_scratch scratch; Vec remainders_store; remainders_store.SetLength(nprimes*CRT_BLK); MatPrime_residue_t *remainders = remainders_store.elts(); for (long i = first; i < last; i++) { ZZ_p *a = A[i].elts(); long jj = 0; for (; jj <= m-CRT_BLK; jj += CRT_BLK) { for (long k = 0; k < nprimes; k++) { const MatPrime_residue_t *x = X.rep[k][i].elts(); for (long j = 0; j < CRT_BLK; j++) remainders[j*nprimes+k] = x[jj+j]; } for (long j = 0; j < CRT_BLK; j++) reconstruct(H, a[jj+j].LoopHole(), remainders + j*nprimes, scratch); } if (jj < m) { for (long k = 0; k < nprimes; k++) { const MatPrime_residue_t *x = X.rep[k][i].elts(); for (long j = 0; j < m-jj; j++) remainders[j*nprimes+k] = x[jj+j]; } for (long j = 0; j < m-jj; j++) reconstruct(H, a[jj+j].LoopHole(), remainders + j*nprimes, scratch); } } NTL_GEXEC_RANGE_END } void mul(mat_ZZ_p_crt_rep& X, const mat_ZZ_p_crt_rep& A, const mat_ZZ_p_crt_rep& B) { long nprimes = A.rep.length(); long n = A.rep[0].NumRows(); long l = A.rep[0].NumCols(); long m = B.rep[0].NumCols(); X.rep.SetLength(nprimes); for (long k = 0; k < nprimes; k++) X.rep[k].SetDims(n, m); bool seq = (double(n)*double(l)*double(m)*double(nprimes) < PAR_THRESH); NTL_GEXEC_RANGE(seq, nprimes, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) zz_pPush push; Mat x, a, b; x.SetDims(n, m); a.SetDims(n, l); b.SetDims(l, m); for (long k = first; k < last; k++) { RestoreMatPrime(k); RawConvert(a, A.rep[k]); RawConvert(b, B.rep[k]); mul(x, a, b); RawConvert(X.rep[k], x); } NTL_GEXEC_RANGE_END } // X = A*transpose(B) void mul_transpose(mat_ZZ_p_crt_rep& X, const mat_ZZ_p_crt_rep& A, const mat_ZZ_p_crt_rep& B) { long nprimes = A.rep.length(); long n = A.rep[0].NumRows(); long l = A.rep[0].NumCols(); long m = B.rep[0].NumRows(); X.rep.SetLength(nprimes); for (long k = 0; k < nprimes; k++) X.rep[k].SetDims(n, m); bool seq = (double(n)*double(l)*double(m)*double(nprimes) < PAR_THRESH); NTL_GEXEC_RANGE(seq, nprimes, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) zz_pPush push; Mat x, a, b; x.SetDims(n, m); a.SetDims(n, l); b.SetDims(l, m); for (long k = first; k < last; k++) { RestoreMatPrime(k); RawConvert(a, A.rep[k]); RawConvertTranspose(b, B.rep[k]); mul(x, a, b); RawConvert(X.rep[k], x); } NTL_GEXEC_RANGE_END } void multi_modular_mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long l = A.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); if (l > NTL_MatPrimeLimit) ResourceError("matrix mul: dimension too large"); mat_ZZ_p_crt_rep x, a, b; to_mat_ZZ_p_crt_rep(a, A); to_mat_ZZ_p_crt_rep(b, B); mul(x, a, b); from_mat_ZZ_p_crt_rep(x, X); } void multi_modular_mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p_crt_rep& B) { long l = A.NumCols(); if (l != B.rep[0].NumRows()) LogicError("matrix mul: dimension mismatch"); if (l > NTL_MatPrimeLimit) ResourceError("matrix mul: dimension too large"); mat_ZZ_p_crt_rep x, a; to_mat_ZZ_p_crt_rep(a, A); mul(x, a, B); from_mat_ZZ_p_crt_rep(x, X); } void multi_modular_mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p_crt_rep& B) { long l = A.NumCols(); if (l != B.rep[0].NumCols()) LogicError("matrix mul: dimension mismatch"); if (l > NTL_MatPrimeLimit) ResourceError("matrix mul: dimension too large"); mat_ZZ_p_crt_rep x, a; to_mat_ZZ_p_crt_rep(a, A); mul_transpose(x, a, B); from_mat_ZZ_p_crt_rep(x, X); } // ******************** mat_ZZ_p_opaque implementation ************ // This could (and maybe eventually will) be implemented using // derived types, if we want run-time polymorphism...we'll see struct mat_ZZ_p_opaque_body_crt : mat_ZZ_p_opaque_body { mat_ZZ_p_crt_rep body; mat_ZZ_p_opaque_body* clone() const { return MakeRaw(*this); } long NumRows() const { return body.rep.length() == 0 ? 0 : body.rep[0].NumRows(); } long NumCols() const { return body.rep.length() == 0 ? 0 : body.rep[0].NumCols(); } void mul(mat_ZZ_p& X, const mat_ZZ_p& A) const { multi_modular_mul(X, A, body); } void mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A) const { multi_modular_mul_transpose(X, A, body); } }; struct mat_ZZ_p_opaque_body_plain : mat_ZZ_p_opaque_body { mat_ZZ_p body; mat_ZZ_p_opaque_body* clone() const { return MakeRaw(*this); } long NumRows() const { return body.NumRows(); } long NumCols() const { return body.NumCols(); } void mul(mat_ZZ_p& X, const mat_ZZ_p& A) const { plain_mul(X, A, body); } void mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A) const { plain_mul_transpose(X, A, body); } }; // This is a "factory" method that makes a mat_ZZ_p_opaque_body // from a matrix A. The matrix A is destroyed in the process. mat_ZZ_p_opaque_body *mat_ZZ_p_opaque_body_move(mat_ZZ_p& A) { if (NTL_USE_MM_MATMUL && A.NumRows() >= 16 && A.NumCols() >= 16) { UniquePtr tmp; tmp.make(); to_mat_ZZ_p_crt_rep(tmp->body, A); A.kill(); return tmp.release(); } else { UniquePtr tmp; tmp.make(); tmp->body.move(A); return tmp.release(); } } // ******************************************************************* void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); if (NTL_USE_MM_MATMUL && n >= 24 && l >= 24 && m >= 24) multi_modular_mul(X, A, B); else plain_mul(X, A, B); } // ******************************************************************* void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } static void mul_aux(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b) { if (&b == &x || A.alias(x)) { vec_ZZ_p tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B) { if (&a == &x) { vec_ZZ_p tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ_p& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } void determinant(ZZ_p& d, const mat_ZZ_p& M_in) { ZZ t1, t2; const ZZ& p = ZZ_p::modulus(); long n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } Vec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n, t1.size()); for (long j = 0; j < n; j++) M[i][j] = rep(M_in[i][j]); } ZZ det; set(det); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (long j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } bool seq = double(n-(k+1))*(n-(k+1))*double(p.size())*double(p.size()) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced ZZ *x = M[i].elts() + (k+1); ZZ *y = M[k].elts() + (k+1); for (long j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } conv(d, det); } long IsIdent(const mat_ZZ_p& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ_p tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } static void solve_impl(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } ZZ t1, t2; const ZZ& p = ZZ_p::modulus(); Vec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n+1, t1.size()); if (trans) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); else for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); M[i][n] = rep(b[i]); } ZZ det; set(det); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (long j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } bool seq = double(n-(k+1))*(n-(k+1))*double(p.size())*double(p.size()) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced ZZ *x = M[i].elts() + (k+1); ZZ *y = M[k].elts() + (k+1); for (long j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } X.SetLength(n); for (long i = n-1; i >= 0; i--) { clear(t1); for (long j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void solve(ZZ_p& d, vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b) { solve_impl(d, x, A, b, true); } void solve(ZZ_p& d, const mat_ZZ_p& A, vec_ZZ_p& x, const vec_ZZ_p& b) { solve_impl(d, x, A, b, false); } void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } const ZZ& p = ZZ_p::modulus(); ZZ t1, t2; ZZ pivot; ZZ pivot_inv; Vec M; // scratch space sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(n, t1.size()); for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); } ZZ det; det = 1; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations bool seq = double(n)*double(n)*double(p.size())*double(p.size()) < PAR_THRESH; bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(pivot, M[i][k], p); if (pivot != 0) { InvMod(pivot_inv, pivot, p); pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); P[k] = pos; pivoting = true; } MulMod(det, det, pivot, p); { // multiply row k by pivot_inv ZZ *y = &M[k][0]; for (long j = 0; j < n; j++) { rem(t2, y[j], p); MulMod(y[j], t2, pivot_inv, p); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ *y = &M[k][0]; ZZ t1, t2; for (long i = first; i < last; i++) { if (i == k) continue; // skip row k ZZ *x = &M[i][0]; rem(t1, x[k], p); NegateMod(t1, t1, p); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i for (long j = 0; j < n; j++) { mul(t2, y[j], t1); add(x[j], x[j], t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { ZZ *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) conv(X[i][j], M[i][j]); conv(d, det); } long gauss(mat_ZZ_p& M_in, long w) { ZZ t1, t2; ZZ piv; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); const ZZ& p = ZZ_p::modulus(); Vec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetSize(m, t1.size()); for (long j = 0; j < m; j++) { M[i][j] = rep(M_in[i][j]); } } long l = 0; for (long k = 0; k < w && l < n; k++) { long pos = -1; for (long i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(piv, M[l][k], p); NegateMod(piv, piv, p); for (long j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } bool seq = double(n-(l+1))*double(m-(k+1))*double(p.size())*double(p.size()) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(l+1), first, last) NTL_IMPORT(m) NTL_IMPORT(k) NTL_IMPORT(l) ZZ t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + l+1; // M[i] = M[i] + M[l]*M[i,k]*piv MulMod(t1, M[i][k], piv, p); clear(M[i][k]); ZZ *x = M[i].elts() + (k+1); ZZ *y = M[l].elts() + (k+1); for (long j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } NTL_GEXEC_RANGE_END l++; } } for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(mat_ZZ_p& M) { return gauss(M, M.NumCols()); } void image(mat_ZZ_p& X, const mat_ZZ_p& A) { mat_ZZ_p M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(mat_ZZ_p& X, const mat_ZZ_p& A) { long m = A.NumRows(); long n = A.NumCols(); const ZZ& p = ZZ_p::modulus(); mat_ZZ_p M; transpose(M, A); long r = gauss(M); if (r == 0) { ident(X, m); return; } X.SetDims(m-r, m); if (m-r == 0 || m == 0) return; Vec D; D.SetLength(m); for (long j = 0; j < m; j++) D[j] = -1; Vec inverses; inverses.SetLength(m); for (long i = 0, j = -1; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } bool seq = double(m-r)*double(r)*double(r)*double(p.size())*double(p.size()) < PAR_THRESH; NTL_GEXEC_RANGE(seq, m-r, first, last) NTL_IMPORT(m) NTL_IMPORT(r) ZZ t1, t2; ZZ_p T3; for (long k = first; k < last; k++) { vec_ZZ_p& v = X[k]; long pos = 0; for (long j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { long i = D[j]; clear(t1); for (long s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } NTL_GEXEC_RANGE_END } void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_ZZ_p& X, long n, const ZZ_p& d_in) { ZZ_p d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_ZZ_p& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ_p& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; mul(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ_p, res); } mat_ZZ_p operator-(const mat_ZZ_p& a) { mat_ZZ_p res; negate(res, a); NTL_OPT_RETURN(mat_ZZ_p, res); } vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b) { vec_ZZ_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } void inv(mat_ZZ_p& X, const mat_ZZ_p& A) { ZZ_p d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ_p T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } void random(mat_ZZ_p& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_ZZ_pE.cpp0000644417616742025610000004706014064716022017307 0ustar gid-shoupvpug-gid-shoupv#include #include NTL_START_IMPL //=================================================== #define PAR_THRESH (40000.0) static double ZZ_pE_SizeInWords() { return double(deg(ZZ_pE::modulus()))*double(ZZ_p::ModulusSize()); } static void mul_aux(Mat& X, const Mat& A, const Mat& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); ZZ_pContext ZZ_p_context; ZZ_p_context.save(); ZZ_pEContext ZZ_pE_context; ZZ_pE_context.save(); double sz = ZZ_pE_SizeInWords(); bool seq = (double(n)*double(l)*double(m)*sz*sz < PAR_THRESH); NTL_GEXEC_RANGE(seq, m, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) ZZ_p_context.restore(); ZZ_pE_context.restore(); long i, j, k; ZZ_pX acc, tmp; Vec B_col; B_col.SetLength(l); for (j = first; j < last; j++) { for (k = 0; k < l; k++) B_col[k] = B[k][j]; for (i = 0; i < n; i++) { clear(acc); for (k = 0; k < l; k++) { mul(tmp, rep(A[i][k]), rep(B_col[k])); add(acc, acc, tmp); } conv(X[i][j], acc); } } NTL_GEXEC_RANGE_END } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { if (&X == &A || &X == &B) { mat_ZZ_pE tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void inv(ZZ_pE& d, Mat& X, const Mat& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } const ZZ_pXModulus& G = ZZ_pE::modulus(); ZZ_pX t1, t2; ZZ_pX pivot; ZZ_pX pivot_inv; Vec< Vec > M; // scratch space M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n); for (long j = 0; j < n; j++) { M[i][j].SetMaxLength(2*deg(G)-1); M[i][j] = rep(A[i][j]); } } ZZ_pX det; det = 1; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations ZZ_pContext ZZ_p_context; ZZ_p_context.save(); double sz = ZZ_pE_SizeInWords(); bool seq = double(n)*double(n)*sz*sz < PAR_THRESH; bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(pivot, M[i][k], G); if (pivot != 0) { InvMod(pivot_inv, pivot, G); pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); P[k] = pos; pivoting = true; } MulMod(det, det, pivot, G); { // multiply row k by pivot_inv ZZ_pX *y = &M[k][0]; for (long j = 0; j < n; j++) { rem(t2, y[j], G); MulMod(y[j], t2, pivot_inv, G); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ_p_context.restore(); ZZ_pX *y = &M[k][0]; ZZ_pX t1, t2; for (long i = first; i < last; i++) { if (i == k) continue; // skip row k ZZ_pX *x = &M[i][0]; rem(t1, x[k], G); negate(t1, t1); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i for (long j = 0; j < n; j++) { mul(t2, y[j], t1); add(x[j], x[j], t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { ZZ_pX *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) conv(X[i][j], M[i][j]); conv(d, det); } static void solve_impl(ZZ_pE& d, Vec& X, const Mat& A, const Vec& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } ZZ_pX t1, t2; const ZZ_pXModulus& G = ZZ_pE::modulus(); Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n+1); for (long j = 0; j < n; j++) M[i][j].SetMaxLength(2*deg(G)-1); if (trans) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); else for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); M[i][n] = rep(b[i]); } ZZ_pX det; set(det); ZZ_pContext ZZ_p_context; ZZ_p_context.save(); double sz = ZZ_pE_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j <= n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ_p_context.restore(); ZZ_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced ZZ_pX *x = M[i].elts() + (k+1); ZZ_pX *y = M[k].elts() + (k+1); for (long j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } X.SetLength(n); for (long i = n-1; i >= 0; i--) { clear(t1); for (long j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void solve(ZZ_pE& d, Vec& x, const Mat& A, const Vec& b) { solve_impl(d, x, A, b, true); } void solve(ZZ_pE& d, const Mat& A, Vec& x, const Vec& b) { solve_impl(d, x, A, b, false); } long gauss(Mat& M_in, long w) { ZZ_pX t1, t2; ZZ_pX piv; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); const ZZ_pXModulus& G = ZZ_pE::modulus(); Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(m); for (long j = 0; j < m; j++) { M[i][j].SetLength(2*deg(G)-1); M[i][j] = rep(M_in[i][j]); } } ZZ_pContext ZZ_p_context; ZZ_p_context.save(); double sz = ZZ_pE_SizeInWords(); long l = 0; for (long k = 0; k < w && l < n; k++) { long pos = -1; for (long i = l; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(piv, M[l][k], G); negate(piv, piv); for (long j = k+1; j < m; j++) { rem(M[l][j], M[l][j], G); } bool seq = double(n-(l+1))*double(m-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(l+1), first, last) NTL_IMPORT(m) NTL_IMPORT(k) NTL_IMPORT(l) ZZ_p_context.restore(); ZZ_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + l+1; // M[i] = M[i] + M[l]*M[i,k]*piv MulMod(t1, M[i][k], piv, G); clear(M[i][k]); ZZ_pX *x = M[i].elts() + (k+1); ZZ_pX *y = M[l].elts() + (k+1); for (long j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } NTL_GEXEC_RANGE_END l++; } } for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(Mat& M) { return gauss(M, M.NumCols()); } void image(Mat& X, const Mat& A) { Mat M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(Mat& X, const Mat& A) { long m = A.NumRows(); long n = A.NumCols(); const ZZ_pXModulus& G = ZZ_pE::modulus(); Mat M; transpose(M, A); long r = gauss(M); if (r == 0) { ident(X, m); return; } X.SetDims(m-r, m); if (m-r == 0 || m == 0) return; Vec D; D.SetLength(m); for (long j = 0; j < m; j++) D[j] = -1; Vec inverses; inverses.SetLength(m); for (long i = 0, j = -1; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } ZZ_pEContext ZZ_pE_context; ZZ_pE_context.save(); ZZ_pContext ZZ_p_context; ZZ_p_context.save(); double sz = ZZ_pE_SizeInWords(); bool seq = double(m-r)*double(r)*double(r)*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, m-r, first, last) NTL_IMPORT(m) NTL_IMPORT(r) ZZ_p_context.restore(); ZZ_pE_context.restore(); ZZ_pX t1, t2; ZZ_pE T3; for (long k = first; k < last; k++) { Vec& v = X[k]; long pos = 0; for (long j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { long i = D[j]; clear(t1); for (long s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } NTL_GEXEC_RANGE_END } void determinant(ZZ_pE& d, const Mat& M_in) { ZZ_pX t1, t2; const ZZ_pXModulus& G = ZZ_pE::modulus(); long n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n); for (long j = 0; j < n; j++) { M[i][j].SetMaxLength(2*deg(G)-1); M[i][j] = rep(M_in[i][j]); } } ZZ_pX det; set(det); ZZ_pContext ZZ_p_context; ZZ_p_context.save(); double sz = ZZ_pE_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j < n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) ZZ_p_context.restore(); ZZ_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced ZZ_pX *x = M[i].elts() + (k+1); ZZ_pX *y = M[k].elts() + (k+1); for (long j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } conv(d, det); } //=================================================== void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } static void mul_aux(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ_pX acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b) { if (&b == &x || A.alias(x)) { vec_ZZ_pE tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ_pX acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B) { if (&a == &x) { vec_ZZ_pE tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_ZZ_pE& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } long IsIdent(const mat_ZZ_pE& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_ZZ_pE tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b_in) { ZZ_pE b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d_in) { ZZ_pE d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_ZZ_pE& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_ZZ_pE& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; add(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE res; sub(res, a, b); NTL_OPT_RETURN(mat_ZZ_pE, res); } mat_ZZ_pE operator-(const mat_ZZ_pE& a) { mat_ZZ_pE res; negate(res, a); NTL_OPT_RETURN(mat_ZZ_pE, res); } vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b) { vec_ZZ_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A) { ZZ_pE d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_ZZ_pE T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } void random(mat_ZZ_pE& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_lzz_p.cpp0000644417616742025610000064072414064716022017464 0ustar gid-shoupvpug-gid-shoupv #include #include #include #ifdef NTL_HAVE_AVX #include #endif NTL_START_IMPL #define PAR_THRESH_SQ (200) #define PAR_THRESH (40000.0) // ******************************************************* // // Matrix Window data structure: perhaps some day this // will be made public. // // ******************************************************* struct mat_window_zz_p { mat_zz_p &A; long r_offset; long c_offset; long nrows; long ncols; mat_window_zz_p(mat_zz_p& _A) : A(_A), r_offset(0), c_offset(0), nrows(A.NumRows()), ncols(A.NumCols()) { } mat_window_zz_p(const mat_window_zz_p& w, long r1, long c1, long r2, long c2) : A(w.A) { if (r1 < 0 || c1 < 0 || r2 < r1 || c2 < c1 || r2-r1 > w.nrows || c2-c1 > w.ncols) LogicError("mat_window_zz_p: bad args"); r_offset = w.r_offset + r1; c_offset = w.c_offset + c1; nrows = r2-r1; ncols = c2-c1; } zz_p * operator[](long i) const { return A[i+r_offset].elts() + c_offset; } long NumRows() const { return nrows; } long NumCols() const { return ncols; } }; struct const_mat_window_zz_p { const mat_zz_p &A; long r_offset; long c_offset; long nrows; long ncols; const_mat_window_zz_p(const mat_zz_p& _A) : A(_A), r_offset(0), c_offset(0), nrows(A.NumRows()), ncols(A.NumCols()) { } const_mat_window_zz_p(const mat_window_zz_p& w) : A(w.A), r_offset(w.r_offset), c_offset(w.c_offset), nrows(w.nrows), ncols(w.ncols) { } const_mat_window_zz_p(const const_mat_window_zz_p& w, long r1, long c1, long r2, long c2) : A(w.A) { if (r1 < 0 || c1 < 0 || r2 < r1 || c2 < c1 || r2-r1 > w.nrows || c2-c1 > w.ncols) LogicError("const_mat_window_zz_p: bad args"); r_offset = w.r_offset + r1; c_offset = w.c_offset + c1; nrows = r2-r1; ncols = c2-c1; } const zz_p * operator[](long i) const { return A[i+r_offset].elts() + c_offset; } long NumRows() const { return nrows; } long NumCols() const { return ncols; } }; void add(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); if (X.NumRows() != n || X.NumCols() != m) LogicError("matrix add: dimension mismatch"); long p = zz_p::modulus(); for (long i = 0; i < n; i++) { zz_p *x = X[i]; const zz_p *a = A[i]; const zz_p *b = B[i]; for (long j = 0; j < m; j++) { x[j].LoopHole() = AddMod(rep(a[j]), rep(b[j]), p); } } } void sub(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); if (X.NumRows() != n || X.NumCols() != m) LogicError("matrix sub: dimension mismatch"); long p = zz_p::modulus(); for (long i = 0; i < n; i++) { zz_p *x = X[i]; const zz_p *a = A[i]; const zz_p *b = B[i]; for (long j = 0; j < m; j++) { x[j].LoopHole() = SubMod(rep(a[j]), rep(b[j]), p); } } } void clear(const mat_window_zz_p& X) { long n = X.NumRows(); long m = X.NumCols(); for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) clear(X[i][j]); } // *********************************************************** void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long p = zz_p::modulus(); for (long i = 0; i < n; i++) { zz_p *x = X[i].elts(); const zz_p *a = A[i].elts(); const zz_p *b = B[i].elts(); for (long j = 0; j < m; j++) { x[j].LoopHole() = AddMod(rep(a[j]), rep(b[j]), p); } } } void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long p = zz_p::modulus(); for (long i = 0; i < n; i++) { zz_p *x = X[i].elts(); const zz_p *a = A[i].elts(); const zz_p *b = B[i].elts(); for (long j = 0; j < m; j++) { x[j].LoopHole() = SubMod(rep(a[j]), rep(b[j]), p); } } } void diag(mat_zz_p& X, long n, zz_p d) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_zz_p& A, long n, zz_p d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } void negate(mat_zz_p& X, const mat_zz_p& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long p = zz_p::modulus(); for (long i = 0; i < n; i++) { zz_p *x = X[i].elts(); const zz_p *a = A[i].elts(); for (long j = 0; j < m; j++) { x[j].LoopHole() = NegateMod(rep(a[j]), p); } } } long IsZero(const mat_zz_p& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_zz_p& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } void ident(mat_zz_p& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } long IsIdent(const mat_zz_p& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_zz_p& X, const mat_zz_p& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_zz_p tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void relaxed_power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e, bool relax) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_zz_p T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) relaxed_inv(X, T1, relax); else X = T1; } // ****************************************************************** // // matrix-vector multiplication code // // ****************************************************************** void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B) { long l = a.length(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); if (m == 0) { x.SetLength(0); } else if (m == 1) { long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long acc, tmp; long k; acc = 0; for(k = 1; k <= l; k++) { tmp = MulMod(rep(a(k)), rep(B(k,1)), p, pinv); acc = AddMod(acc, tmp, p); } x.SetLength(1); x(1).LoopHole() = acc; } else { // m > 1. precondition and EXEC_RANGE long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); NTL_TLS_LOCAL(vec_long, mul_aux_vec); vec_long::Watcher watch_mul_aux_vec(mul_aux_vec); mul_aux_vec.SetLength(m); long *acc = mul_aux_vec.elts(); const zz_p* ap = a.elts(); for (long j = 0; j < m; j++) acc[j] = 0; const bool seq = double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, m, first, last) { for (long k = 0; k < l; k++) { long aa = rep(ap[k]); if (aa != 0) { const zz_p* bp = B[k].elts(); long T1; mulmod_precon_t aapinv = PrepMulModPrecon(aa, p, pinv); for (long j = first; j < last; j++) { T1 = MulModPrecon(rep(bp[j]), aa, p, aapinv); acc[j] = AddMod(acc[j], T1, p); } } } } NTL_GEXEC_RANGE_END x.SetLength(m); zz_p *xp = x.elts(); for (long j = 0; j < m; j++) xp[j].LoopHole() = acc[j]; } } void mul_aux(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); zz_p* xp = x.elts(); long p = zz_p::modulus(); const zz_p* bp = b.elts(); const bool seq = double(n)*double(l) < PAR_THRESH; #ifdef NTL_HAVE_LL_TYPE if (InnerProd_L_viable(l, p)) { sp_reduce_struct red_struct = zz_p::red_struct(); long bound = InnerProd_L_bound(p); NTL_GEXEC_RANGE(seq, n, first, last) { for (long i = first; i < last; i++) { xp[i].LoopHole() = InnerProd_L(A[i].elts(), bp, l, p, red_struct, bound); } } NTL_GEXEC_RANGE_END } else { sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); NTL_GEXEC_RANGE(seq, n, first, last) { for (long i = first; i < last; i++) { xp[i].LoopHole() = InnerProd_LL(A[i].elts(), bp, l, p, ll_red_struct); } } NTL_GEXEC_RANGE_END } #else mulmod_t pinv = zz_p::ModulusInverse(); if (n <= 1) { for (long i = 0; i < n; i++) { long acc = 0; const zz_p* ap = A[i].elts(); for (long k = 0; k < l; k++) { long tmp = MulMod(rep(ap[k]), rep(bp[k]), p, pinv); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } } else { NTL_TLS_LOCAL(Vec, precon_vec); Vec::Watcher watch_precon_vec(precon_vec); precon_vec.SetLength(l); mulmod_precon_t *bpinv = precon_vec.elts(); for (long k = 0; k < l; k++) bpinv[k] = PrepMulModPrecon(rep(bp[k]), p, pinv); NTL_GEXEC_RANGE(seq, n, first, last) { for (long i = first; i < last; i++) { long acc = 0; const zz_p* ap = A[i].elts(); for (long k = 0; k < l; k++) { long tmp = MulModPrecon(rep(ap[k]), rep(bp[k]), p, bpinv[k]); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } } NTL_GEXEC_RANGE_END } #endif } void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { if (&b == &x || A.alias(x)) { vec_zz_p tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); if (n == 0 || m == 0 || (n == 1 && m == 1)) { long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } else { long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long bb = rep(b); mulmod_precon_t bpinv = PrepMulModPrecon(bb, p, pinv); const bool seq = double(n)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n, first, last) long i, j; for (i = first; i < last; i++) { const zz_p *ap = A[i].elts(); zz_p *xp = X[i].elts(); for (j = 0; j < m; j++) xp[j].LoopHole() = MulModPrecon(rep(ap[j]), bb, p, bpinv); } NTL_GEXEC_RANGE_END } } void mul(mat_zz_p& X, const mat_zz_p& A, long b_in) { zz_p b; b = b_in; mul(X, A, b); } // ****************************************************************** // // Code shared by block-matrix code // // ****************************************************************** //#undef NTL_HAVE_AVX //#undef NTL_HAVE_FMA //#undef NTL_HAVE_AVX512F // for testing purposes #if (defined(NTL_HAVE_AVX512F) && defined(NTL_AVOID_AVX512)) #undef NTL_HAVE_AVX512F #endif #define MAT_BLK_SZ (32) #ifdef NTL_HAVE_LL_TYPE #ifdef NTL_HAVE_AVX #define MAX_DBL_INT ((1L << NTL_DOUBLE_PRECISION)-1) // max int representable exactly as a double // this assumes NTL_DBL_PRECISION <= NTL_BITS_PER_LONG-2, which is // checked in the code that tests for HAVE_AVX, but we check it here as // well #if (NTL_DBL_PRECISION > NTL_BITS_PER_LONG-2) #error "NTL_DBL_PRECISION > NTL_BITS_PER_LONG-2" #endif // MUL_ADD(a, b, c): a += b*c #ifdef NTL_HAVE_FMA #define MUL_ADD(a, b, c) a = _mm256_fmadd_pd(b, c, a) #else #define MUL_ADD(a, b, c) a = _mm256_add_pd(a, _mm256_mul_pd(b, c)) #endif #ifdef NTL_HAVE_AVX512F #define MUL_ADD512(a, b, c) a = _mm512_fmadd_pd(b, c, a) #endif #ifdef NTL_HAVE_AVX512F static void muladd1_by_32(double *x, const double *a, const double *b, long n) { __m512d avec0, bvec; __m512d acc00, acc01, acc02, acc03; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); acc02=_mm512_load_pd(x + 2*8 + 0*MAT_BLK_SZ); acc03=_mm512_load_pd(x + 3*8 + 0*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+2*8]); MUL_ADD512(acc02, avec0, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+3*8]); MUL_ADD512(acc03, avec0, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); _mm512_store_pd(x + 2*8 + 0*MAT_BLK_SZ, acc02); _mm512_store_pd(x + 3*8 + 0*MAT_BLK_SZ, acc03); } static void muladd2_by_32(double *x, const double *a, const double *b, long n) { __m512d avec0, avec1, bvec; __m512d acc00, acc01, acc02, acc03; __m512d acc10, acc11, acc12, acc13; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); acc02=_mm512_load_pd(x + 2*8 + 0*MAT_BLK_SZ); acc03=_mm512_load_pd(x + 3*8 + 0*MAT_BLK_SZ); acc10=_mm512_load_pd(x + 0*8 + 1*MAT_BLK_SZ); acc11=_mm512_load_pd(x + 1*8 + 1*MAT_BLK_SZ); acc12=_mm512_load_pd(x + 2*8 + 1*MAT_BLK_SZ); acc13=_mm512_load_pd(x + 3*8 + 1*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); avec1 = _mm512_set1_pd(a[i+1*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); MUL_ADD512(acc10, avec1, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); MUL_ADD512(acc11, avec1, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+2*8]); MUL_ADD512(acc02, avec0, bvec); MUL_ADD512(acc12, avec1, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+3*8]); MUL_ADD512(acc03, avec0, bvec); MUL_ADD512(acc13, avec1, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); _mm512_store_pd(x + 2*8 + 0*MAT_BLK_SZ, acc02); _mm512_store_pd(x + 3*8 + 0*MAT_BLK_SZ, acc03); _mm512_store_pd(x + 0*8 + 1*MAT_BLK_SZ, acc10); _mm512_store_pd(x + 1*8 + 1*MAT_BLK_SZ, acc11); _mm512_store_pd(x + 2*8 + 1*MAT_BLK_SZ, acc12); _mm512_store_pd(x + 3*8 + 1*MAT_BLK_SZ, acc13); } static void muladd3_by_32(double *x, const double *a, const double *b, long n) { __m512d avec0, avec1, avec2, bvec; __m512d acc00, acc01, acc02, acc03; __m512d acc10, acc11, acc12, acc13; __m512d acc20, acc21, acc22, acc23; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); acc02=_mm512_load_pd(x + 2*8 + 0*MAT_BLK_SZ); acc03=_mm512_load_pd(x + 3*8 + 0*MAT_BLK_SZ); acc10=_mm512_load_pd(x + 0*8 + 1*MAT_BLK_SZ); acc11=_mm512_load_pd(x + 1*8 + 1*MAT_BLK_SZ); acc12=_mm512_load_pd(x + 2*8 + 1*MAT_BLK_SZ); acc13=_mm512_load_pd(x + 3*8 + 1*MAT_BLK_SZ); acc20=_mm512_load_pd(x + 0*8 + 2*MAT_BLK_SZ); acc21=_mm512_load_pd(x + 1*8 + 2*MAT_BLK_SZ); acc22=_mm512_load_pd(x + 2*8 + 2*MAT_BLK_SZ); acc23=_mm512_load_pd(x + 3*8 + 2*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); avec1 = _mm512_set1_pd(a[i+1*MAT_BLK_SZ]); avec2 = _mm512_set1_pd(a[i+2*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); MUL_ADD512(acc10, avec1, bvec); MUL_ADD512(acc20, avec2, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); MUL_ADD512(acc11, avec1, bvec); MUL_ADD512(acc21, avec2, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+2*8]); MUL_ADD512(acc02, avec0, bvec); MUL_ADD512(acc12, avec1, bvec); MUL_ADD512(acc22, avec2, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+3*8]); MUL_ADD512(acc03, avec0, bvec); MUL_ADD512(acc13, avec1, bvec); MUL_ADD512(acc23, avec2, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); _mm512_store_pd(x + 2*8 + 0*MAT_BLK_SZ, acc02); _mm512_store_pd(x + 3*8 + 0*MAT_BLK_SZ, acc03); _mm512_store_pd(x + 0*8 + 1*MAT_BLK_SZ, acc10); _mm512_store_pd(x + 1*8 + 1*MAT_BLK_SZ, acc11); _mm512_store_pd(x + 2*8 + 1*MAT_BLK_SZ, acc12); _mm512_store_pd(x + 3*8 + 1*MAT_BLK_SZ, acc13); _mm512_store_pd(x + 0*8 + 2*MAT_BLK_SZ, acc20); _mm512_store_pd(x + 1*8 + 2*MAT_BLK_SZ, acc21); _mm512_store_pd(x + 2*8 + 2*MAT_BLK_SZ, acc22); _mm512_store_pd(x + 3*8 + 2*MAT_BLK_SZ, acc23); } static void muladd1_by_16(double *x, const double *a, const double *b, long n) { __m512d avec0, bvec; __m512d acc00, acc01; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); } static void muladd2_by_16(double *x, const double *a, const double *b, long n) { __m512d avec0, avec1, bvec; __m512d acc00, acc01; __m512d acc10, acc11; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); acc10=_mm512_load_pd(x + 0*8 + 1*MAT_BLK_SZ); acc11=_mm512_load_pd(x + 1*8 + 1*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); avec1 = _mm512_set1_pd(a[i+1*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); MUL_ADD512(acc10, avec1, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); MUL_ADD512(acc11, avec1, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); _mm512_store_pd(x + 0*8 + 1*MAT_BLK_SZ, acc10); _mm512_store_pd(x + 1*8 + 1*MAT_BLK_SZ, acc11); } static void muladd3_by_16(double *x, const double *a, const double *b, long n) { __m512d avec0, avec1, avec2, bvec; __m512d acc00, acc01; __m512d acc10, acc11; __m512d acc20, acc21; acc00=_mm512_load_pd(x + 0*8 + 0*MAT_BLK_SZ); acc01=_mm512_load_pd(x + 1*8 + 0*MAT_BLK_SZ); acc10=_mm512_load_pd(x + 0*8 + 1*MAT_BLK_SZ); acc11=_mm512_load_pd(x + 1*8 + 1*MAT_BLK_SZ); acc20=_mm512_load_pd(x + 0*8 + 2*MAT_BLK_SZ); acc21=_mm512_load_pd(x + 1*8 + 2*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm512_set1_pd(a[i+0*MAT_BLK_SZ]); avec1 = _mm512_set1_pd(a[i+1*MAT_BLK_SZ]); avec2 = _mm512_set1_pd(a[i+2*MAT_BLK_SZ]); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+0*8]); MUL_ADD512(acc00, avec0, bvec); MUL_ADD512(acc10, avec1, bvec); MUL_ADD512(acc20, avec2, bvec); bvec = _mm512_load_pd(&b[i*MAT_BLK_SZ+1*8]); MUL_ADD512(acc01, avec0, bvec); MUL_ADD512(acc11, avec1, bvec); MUL_ADD512(acc21, avec2, bvec); } _mm512_store_pd(x + 0*8 + 0*MAT_BLK_SZ, acc00); _mm512_store_pd(x + 1*8 + 0*MAT_BLK_SZ, acc01); _mm512_store_pd(x + 0*8 + 1*MAT_BLK_SZ, acc10); _mm512_store_pd(x + 1*8 + 1*MAT_BLK_SZ, acc11); _mm512_store_pd(x + 0*8 + 2*MAT_BLK_SZ, acc20); _mm512_store_pd(x + 1*8 + 2*MAT_BLK_SZ, acc21); } #else static void muladd1_by_32(double *x, const double *a, const double *b, long n) { __m256d avec, bvec; __m256d acc0=_mm256_load_pd(x + 0*4); __m256d acc1=_mm256_load_pd(x + 1*4); __m256d acc2=_mm256_load_pd(x + 2*4); __m256d acc3=_mm256_load_pd(x + 3*4); __m256d acc4=_mm256_load_pd(x + 4*4); __m256d acc5=_mm256_load_pd(x + 5*4); __m256d acc6=_mm256_load_pd(x + 6*4); __m256d acc7=_mm256_load_pd(x + 7*4); for (long i = 0; i < n; i++) { avec = _mm256_broadcast_sd(a); a++; bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc0, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc1, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc2, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc3, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc4, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc5, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc6, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc7, avec, bvec); } _mm256_store_pd(x + 0*4, acc0); _mm256_store_pd(x + 1*4, acc1); _mm256_store_pd(x + 2*4, acc2); _mm256_store_pd(x + 3*4, acc3); _mm256_store_pd(x + 4*4, acc4); _mm256_store_pd(x + 5*4, acc5); _mm256_store_pd(x + 6*4, acc6); _mm256_store_pd(x + 7*4, acc7); } static void muladd2_by_32(double *x, const double *a, const double *b, long n) { __m256d avec0, avec1, bvec; __m256d acc00, acc01, acc02, acc03; __m256d acc10, acc11, acc12, acc13; // round 0 acc00=_mm256_load_pd(x + 0*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 1*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 2*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 3*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 0*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 1*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 2*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 3*4 + 1*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); } _mm256_store_pd(x + 0*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 1*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 2*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 3*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 0*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 1*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 2*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 3*4 + 1*MAT_BLK_SZ, acc13); // round 1 acc00=_mm256_load_pd(x + 4*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 5*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 6*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 7*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 4*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 5*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 6*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 7*4 + 1*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4+MAT_BLK_SZ/2]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4+MAT_BLK_SZ/2]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4+MAT_BLK_SZ/2]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4+MAT_BLK_SZ/2]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); } _mm256_store_pd(x + 4*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 5*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 6*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 7*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 4*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 5*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 6*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 7*4 + 1*MAT_BLK_SZ, acc13); } // NOTE: this makes things slower on an AVX1 platform --- not enough registers // it could be faster on AVX2/FMA, where there should be enough registers static void muladd3_by_32(double *x, const double *a, const double *b, long n) { __m256d avec0, avec1, avec2, bvec; __m256d acc00, acc01, acc02, acc03; __m256d acc10, acc11, acc12, acc13; __m256d acc20, acc21, acc22, acc23; // round 0 acc00=_mm256_load_pd(x + 0*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 1*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 2*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 3*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 0*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 1*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 2*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 3*4 + 1*MAT_BLK_SZ); acc20=_mm256_load_pd(x + 0*4 + 2*MAT_BLK_SZ); acc21=_mm256_load_pd(x + 1*4 + 2*MAT_BLK_SZ); acc22=_mm256_load_pd(x + 2*4 + 2*MAT_BLK_SZ); acc23=_mm256_load_pd(x + 3*4 + 2*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); avec2 = _mm256_broadcast_sd(&a[i+2*MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); MUL_ADD(acc20, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); MUL_ADD(acc21, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); MUL_ADD(acc22, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); MUL_ADD(acc23, avec2, bvec); } _mm256_store_pd(x + 0*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 1*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 2*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 3*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 0*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 1*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 2*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 3*4 + 1*MAT_BLK_SZ, acc13); _mm256_store_pd(x + 0*4 + 2*MAT_BLK_SZ, acc20); _mm256_store_pd(x + 1*4 + 2*MAT_BLK_SZ, acc21); _mm256_store_pd(x + 2*4 + 2*MAT_BLK_SZ, acc22); _mm256_store_pd(x + 3*4 + 2*MAT_BLK_SZ, acc23); // round 1 acc00=_mm256_load_pd(x + 4*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 5*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 6*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 7*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 4*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 5*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 6*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 7*4 + 1*MAT_BLK_SZ); acc20=_mm256_load_pd(x + 4*4 + 2*MAT_BLK_SZ); acc21=_mm256_load_pd(x + 5*4 + 2*MAT_BLK_SZ); acc22=_mm256_load_pd(x + 6*4 + 2*MAT_BLK_SZ); acc23=_mm256_load_pd(x + 7*4 + 2*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); avec2 = _mm256_broadcast_sd(&a[i+2*MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4+MAT_BLK_SZ/2]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); MUL_ADD(acc20, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4+MAT_BLK_SZ/2]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); MUL_ADD(acc21, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4+MAT_BLK_SZ/2]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); MUL_ADD(acc22, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4+MAT_BLK_SZ/2]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); MUL_ADD(acc23, avec2, bvec); } _mm256_store_pd(x + 4*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 5*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 6*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 7*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 4*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 5*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 6*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 7*4 + 1*MAT_BLK_SZ, acc13); _mm256_store_pd(x + 4*4 + 2*MAT_BLK_SZ, acc20); _mm256_store_pd(x + 5*4 + 2*MAT_BLK_SZ, acc21); _mm256_store_pd(x + 6*4 + 2*MAT_BLK_SZ, acc22); _mm256_store_pd(x + 7*4 + 2*MAT_BLK_SZ, acc23); } static void muladd1_by_16(double *x, const double *a, const double *b, long n) { __m256d avec, bvec; __m256d acc0=_mm256_load_pd(x + 0*4); __m256d acc1=_mm256_load_pd(x + 1*4); __m256d acc2=_mm256_load_pd(x + 2*4); __m256d acc3=_mm256_load_pd(x + 3*4); for (long i = 0; i < n; i++) { avec = _mm256_broadcast_sd(a); a++; bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc0, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc1, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc2, avec, bvec); bvec = _mm256_load_pd(b); b += 4; MUL_ADD(acc3, avec, bvec); b += 16; } _mm256_store_pd(x + 0*4, acc0); _mm256_store_pd(x + 1*4, acc1); _mm256_store_pd(x + 2*4, acc2); _mm256_store_pd(x + 3*4, acc3); } static void muladd2_by_16(double *x, const double *a, const double *b, long n) { __m256d avec0, avec1, bvec; __m256d acc00, acc01, acc02, acc03; __m256d acc10, acc11, acc12, acc13; // round 0 acc00=_mm256_load_pd(x + 0*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 1*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 2*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 3*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 0*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 1*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 2*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 3*4 + 1*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); } _mm256_store_pd(x + 0*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 1*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 2*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 3*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 0*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 1*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 2*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 3*4 + 1*MAT_BLK_SZ, acc13); } static void muladd3_by_16(double *x, const double *a, const double *b, long n) { __m256d avec0, avec1, avec2, bvec; __m256d acc00, acc01, acc02, acc03; __m256d acc10, acc11, acc12, acc13; __m256d acc20, acc21, acc22, acc23; // round 0 acc00=_mm256_load_pd(x + 0*4 + 0*MAT_BLK_SZ); acc01=_mm256_load_pd(x + 1*4 + 0*MAT_BLK_SZ); acc02=_mm256_load_pd(x + 2*4 + 0*MAT_BLK_SZ); acc03=_mm256_load_pd(x + 3*4 + 0*MAT_BLK_SZ); acc10=_mm256_load_pd(x + 0*4 + 1*MAT_BLK_SZ); acc11=_mm256_load_pd(x + 1*4 + 1*MAT_BLK_SZ); acc12=_mm256_load_pd(x + 2*4 + 1*MAT_BLK_SZ); acc13=_mm256_load_pd(x + 3*4 + 1*MAT_BLK_SZ); acc20=_mm256_load_pd(x + 0*4 + 2*MAT_BLK_SZ); acc21=_mm256_load_pd(x + 1*4 + 2*MAT_BLK_SZ); acc22=_mm256_load_pd(x + 2*4 + 2*MAT_BLK_SZ); acc23=_mm256_load_pd(x + 3*4 + 2*MAT_BLK_SZ); for (long i = 0; i < n; i++) { avec0 = _mm256_broadcast_sd(&a[i]); avec1 = _mm256_broadcast_sd(&a[i+MAT_BLK_SZ]); avec2 = _mm256_broadcast_sd(&a[i+2*MAT_BLK_SZ]); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+0*4]); MUL_ADD(acc00, avec0, bvec); MUL_ADD(acc10, avec1, bvec); MUL_ADD(acc20, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+1*4]); MUL_ADD(acc01, avec0, bvec); MUL_ADD(acc11, avec1, bvec); MUL_ADD(acc21, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+2*4]); MUL_ADD(acc02, avec0, bvec); MUL_ADD(acc12, avec1, bvec); MUL_ADD(acc22, avec2, bvec); bvec = _mm256_load_pd(&b[i*MAT_BLK_SZ+3*4]); MUL_ADD(acc03, avec0, bvec); MUL_ADD(acc13, avec1, bvec); MUL_ADD(acc23, avec2, bvec); } _mm256_store_pd(x + 0*4 + 0*MAT_BLK_SZ, acc00); _mm256_store_pd(x + 1*4 + 0*MAT_BLK_SZ, acc01); _mm256_store_pd(x + 2*4 + 0*MAT_BLK_SZ, acc02); _mm256_store_pd(x + 3*4 + 0*MAT_BLK_SZ, acc03); _mm256_store_pd(x + 0*4 + 1*MAT_BLK_SZ, acc10); _mm256_store_pd(x + 1*4 + 1*MAT_BLK_SZ, acc11); _mm256_store_pd(x + 2*4 + 1*MAT_BLK_SZ, acc12); _mm256_store_pd(x + 3*4 + 1*MAT_BLK_SZ, acc13); _mm256_store_pd(x + 0*4 + 2*MAT_BLK_SZ, acc20); _mm256_store_pd(x + 1*4 + 2*MAT_BLK_SZ, acc21); _mm256_store_pd(x + 2*4 + 2*MAT_BLK_SZ, acc22); _mm256_store_pd(x + 3*4 + 2*MAT_BLK_SZ, acc23); } #endif static inline void muladd_all_by_32(long first, long last, double *x, const double *a, const double *b, long n) { long i = first; #if (defined(NTL_HAVE_FMA) || defined(NTL_HAVE_AVX512F)) // process three rows at a time for (; i <= last-3; i+=3) muladd3_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); for (; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); #else // process only two rows at a time: not enough registers :-( for (; i <= last-2; i+=2) muladd2_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); for (; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); #endif } static inline void muladd_all_by_16(long first, long last, double *x, const double *a, const double *b, long n) { long i = first; #if (defined(NTL_HAVE_FMA) || defined(NTL_HAVE_AVX512F)) // processing three rows at a time is faster for (; i <= last-3; i+=3) muladd3_by_16(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); for (; i < last; i++) muladd1_by_16(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); #else // process only two rows at a time: not enough registers :-( for (; i <= last-2; i+=2) muladd2_by_16(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); for (; i < last; i++) muladd1_by_16(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); #endif } static inline void muladd_all_by_32_width(long first, long last, double *x, const double *a, const double *b, long n, long width) { if (width > MAT_BLK_SZ/2) muladd_all_by_32(first, last, x, a, b, n); else muladd_all_by_16(first, last, x, a, b, n); } // muladd_interval1 used in alt_inv_DD and alt_tri_DD // muladd_interval used in blk_inv_DD and blk_tri_DD, with an // argument of MAT_BLK_SZ // this assumes n is a multiple of 16 static inline void muladd_interval(double * NTL_RESTRICT x, double * NTL_RESTRICT y, double c, long n) { __m256d xvec0, xvec1, xvec2, xvec3; __m256d yvec0, yvec1, yvec2, yvec3; __m256d cvec = _mm256_broadcast_sd(&c); for (long i = 0; i < n; i += 16, x += 16, y += 16) { xvec0 = _mm256_load_pd(x+0*4); xvec1 = _mm256_load_pd(x+1*4); xvec2 = _mm256_load_pd(x+2*4); xvec3 = _mm256_load_pd(x+3*4); yvec0 = _mm256_load_pd(y+0*4); yvec1 = _mm256_load_pd(y+1*4); yvec2 = _mm256_load_pd(y+2*4); yvec3 = _mm256_load_pd(y+3*4); MUL_ADD(xvec0, yvec0, cvec); MUL_ADD(xvec1, yvec1, cvec); MUL_ADD(xvec2, yvec2, cvec); MUL_ADD(xvec3, yvec3, cvec); _mm256_store_pd(x + 0*4, xvec0); _mm256_store_pd(x + 1*4, xvec1); _mm256_store_pd(x + 2*4, xvec2); _mm256_store_pd(x + 3*4, xvec3); } } // this one is more general: does not assume that n is a // multiple of 16 static inline void muladd_interval1(double * NTL_RESTRICT x, double * NTL_RESTRICT y, double c, long n) { __m256d xvec0, xvec1, xvec2, xvec3; __m256d yvec0, yvec1, yvec2, yvec3; __m256d cvec; if (n >= 4) cvec = _mm256_broadcast_sd(&c); long i=0; for (; i <= n-16; i += 16, x += 16, y += 16) { xvec0 = _mm256_load_pd(x+0*4); xvec1 = _mm256_load_pd(x+1*4); xvec2 = _mm256_load_pd(x+2*4); xvec3 = _mm256_load_pd(x+3*4); yvec0 = _mm256_load_pd(y+0*4); yvec1 = _mm256_load_pd(y+1*4); yvec2 = _mm256_load_pd(y+2*4); yvec3 = _mm256_load_pd(y+3*4); MUL_ADD(xvec0, yvec0, cvec); MUL_ADD(xvec1, yvec1, cvec); MUL_ADD(xvec2, yvec2, cvec); MUL_ADD(xvec3, yvec3, cvec); _mm256_store_pd(x + 0*4, xvec0); _mm256_store_pd(x + 1*4, xvec1); _mm256_store_pd(x + 2*4, xvec2); _mm256_store_pd(x + 3*4, xvec3); } for (; i <= n-4; i += 4, x += 4, y += 4) { xvec0 = _mm256_load_pd(x+0*4); yvec0 = _mm256_load_pd(y+0*4); MUL_ADD(xvec0, yvec0, cvec); _mm256_store_pd(x + 0*4, xvec0); } for (; i < n; i++, x++, y++) { *x += (*y)*c; } } #endif //#define DO_MUL(a, b) ((unsigned long) (long(a)*long(b))) static inline unsigned long DO_MUL(unsigned long a, unsigned long b) { return a*b; } static inline void muladd_interval(unsigned long * NTL_RESTRICT x, unsigned long * NTL_RESTRICT y, unsigned long c, long n) { for (long i = 0; i < n; i++) x[i] += DO_MUL(y[i], c); } static void muladd1_by_32(unsigned long *x, const unsigned long *a, const unsigned long *b, long n) { for (long j = 0; j < MAT_BLK_SZ; j++) { unsigned long sum = x[j]; long i = 0; for (; i <= n-4; i += 4) { sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); } for (; i < n; i++) sum += DO_MUL(a[i], b[i]); x[j] = sum; b += MAT_BLK_SZ; } } static void muladd1_by_32_width(unsigned long *x, const unsigned long *a, const unsigned long *b, long n, long width) { for (long j = 0; j < width; j++) { unsigned long sum = x[j]; long i = 0; for (; i <= n-4; i += 4) { sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); } for (; i < n; i++) sum += DO_MUL(a[i], b[i]); x[j] = sum; b += MAT_BLK_SZ; } } // experiment with shorter int's static void muladd1_by_32(unsigned long *x, const unsigned int *a, const unsigned int *b, long n) { for (long j = 0; j < MAT_BLK_SZ; j++) { unsigned long sum = x[j]; long i = 0; for (; i <= n-4; i += 4) { sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); } for (; i < n; i++) sum += DO_MUL(a[i], b[i]); x[j] = sum; b += MAT_BLK_SZ; } } static void muladd1_by_32_width(unsigned long *x, const unsigned int *a, const unsigned int *b, long n, long width) { for (long j = 0; j < width; j++) { unsigned long sum = x[j]; long i = 0; for (; i <= n-4; i += 4) { sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); } for (; i < n; i++) sum += DO_MUL(a[i], b[i]); x[j] = sum; b += MAT_BLK_SZ; } } #if 0 static void muladd1_by_32_full(unsigned long *x, const unsigned long *a, const unsigned long *b) { for (long j = 0; j < MAT_BLK_SZ; j++) { unsigned long sum = x[j]; long i = 0; sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); sum += DO_MUL(a[i+4], b[i+4]); sum += DO_MUL(a[i+5], b[i+5]); sum += DO_MUL(a[i+6], b[i+6]); sum += DO_MUL(a[i+7], b[i+7]); sum += DO_MUL(a[i+8], b[i+8]); sum += DO_MUL(a[i+9], b[i+9]); sum += DO_MUL(a[i+10], b[i+10]); sum += DO_MUL(a[i+11], b[i+11]); sum += DO_MUL(a[i+12], b[i+12]); sum += DO_MUL(a[i+13], b[i+13]); sum += DO_MUL(a[i+14], b[i+14]); sum += DO_MUL(a[i+15], b[i+15]); sum += DO_MUL(a[i+16], b[i+16]); sum += DO_MUL(a[i+17], b[i+17]); sum += DO_MUL(a[i+18], b[i+18]); sum += DO_MUL(a[i+19], b[i+19]); sum += DO_MUL(a[i+20], b[i+20]); sum += DO_MUL(a[i+21], b[i+21]); sum += DO_MUL(a[i+22], b[i+22]); sum += DO_MUL(a[i+23], b[i+23]); sum += DO_MUL(a[i+24], b[i+24]); sum += DO_MUL(a[i+25], b[i+25]); sum += DO_MUL(a[i+26], b[i+26]); sum += DO_MUL(a[i+27], b[i+27]); sum += DO_MUL(a[i+28], b[i+28]); sum += DO_MUL(a[i+29], b[i+29]); sum += DO_MUL(a[i+30], b[i+30]); sum += DO_MUL(a[i+31], b[i+31]); x[j] = sum; b += MAT_BLK_SZ; } } #else // this version is faster (by about 25%) on a Sandybridge machine #define ONE_STEP_L(i) \ sum += DO_MUL(a[i],b[i]);\ sum_1 += DO_MUL(a[i],b_1[i]);\ sum_2 += DO_MUL(a[i],b_2[i]);\ sum_3 += DO_MUL(a[i],b_3[i])\ static void muladd1_by_32_full(unsigned long *x, const unsigned long *a, const unsigned long *b) { for (long j = 0; j < MAT_BLK_SZ; j+=4) { unsigned long sum = x[j]; unsigned long sum_1 = x[j+1]; unsigned long sum_2 = x[j+2]; unsigned long sum_3 = x[j+3]; const unsigned long *b_1 = b+MAT_BLK_SZ; const unsigned long *b_2 = b+2*MAT_BLK_SZ; const unsigned long *b_3 = b+3*MAT_BLK_SZ; ONE_STEP_L(0); ONE_STEP_L(1); ONE_STEP_L(2); ONE_STEP_L(3); ONE_STEP_L(4); ONE_STEP_L(5); ONE_STEP_L(6); ONE_STEP_L(7); ONE_STEP_L(8); ONE_STEP_L(9); ONE_STEP_L(10); ONE_STEP_L(11); ONE_STEP_L(12); ONE_STEP_L(13); ONE_STEP_L(14); ONE_STEP_L(15); ONE_STEP_L(16); ONE_STEP_L(17); ONE_STEP_L(18); ONE_STEP_L(19); ONE_STEP_L(20); ONE_STEP_L(21); ONE_STEP_L(22); ONE_STEP_L(23); ONE_STEP_L(24); ONE_STEP_L(25); ONE_STEP_L(26); ONE_STEP_L(27); ONE_STEP_L(28); ONE_STEP_L(29); ONE_STEP_L(30); ONE_STEP_L(31); x[j] = sum; x[j+1] = sum_1; x[j+2] = sum_2; x[j+3] = sum_3; b += 4*MAT_BLK_SZ; } } static void muladd1_by_32_full_width(unsigned long *x, const unsigned long *a, const unsigned long *b, long width) { long j = 0; for (; j <= width-4; j+=4) { unsigned long sum = x[j]; unsigned long sum_1 = x[j+1]; unsigned long sum_2 = x[j+2]; unsigned long sum_3 = x[j+3]; const unsigned long *b_1 = b+MAT_BLK_SZ; const unsigned long *b_2 = b+2*MAT_BLK_SZ; const unsigned long *b_3 = b+3*MAT_BLK_SZ; ONE_STEP_L(0); ONE_STEP_L(1); ONE_STEP_L(2); ONE_STEP_L(3); ONE_STEP_L(4); ONE_STEP_L(5); ONE_STEP_L(6); ONE_STEP_L(7); ONE_STEP_L(8); ONE_STEP_L(9); ONE_STEP_L(10); ONE_STEP_L(11); ONE_STEP_L(12); ONE_STEP_L(13); ONE_STEP_L(14); ONE_STEP_L(15); ONE_STEP_L(16); ONE_STEP_L(17); ONE_STEP_L(18); ONE_STEP_L(19); ONE_STEP_L(20); ONE_STEP_L(21); ONE_STEP_L(22); ONE_STEP_L(23); ONE_STEP_L(24); ONE_STEP_L(25); ONE_STEP_L(26); ONE_STEP_L(27); ONE_STEP_L(28); ONE_STEP_L(29); ONE_STEP_L(30); ONE_STEP_L(31); x[j] = sum; x[j+1] = sum_1; x[j+2] = sum_2; x[j+3] = sum_3; b += 4*MAT_BLK_SZ; } for (; j < width; j++) { unsigned long sum = x[j]; long i = 0; sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); sum += DO_MUL(a[i+4], b[i+4]); sum += DO_MUL(a[i+5], b[i+5]); sum += DO_MUL(a[i+6], b[i+6]); sum += DO_MUL(a[i+7], b[i+7]); sum += DO_MUL(a[i+8], b[i+8]); sum += DO_MUL(a[i+9], b[i+9]); sum += DO_MUL(a[i+10], b[i+10]); sum += DO_MUL(a[i+11], b[i+11]); sum += DO_MUL(a[i+12], b[i+12]); sum += DO_MUL(a[i+13], b[i+13]); sum += DO_MUL(a[i+14], b[i+14]); sum += DO_MUL(a[i+15], b[i+15]); sum += DO_MUL(a[i+16], b[i+16]); sum += DO_MUL(a[i+17], b[i+17]); sum += DO_MUL(a[i+18], b[i+18]); sum += DO_MUL(a[i+19], b[i+19]); sum += DO_MUL(a[i+20], b[i+20]); sum += DO_MUL(a[i+21], b[i+21]); sum += DO_MUL(a[i+22], b[i+22]); sum += DO_MUL(a[i+23], b[i+23]); sum += DO_MUL(a[i+24], b[i+24]); sum += DO_MUL(a[i+25], b[i+25]); sum += DO_MUL(a[i+26], b[i+26]); sum += DO_MUL(a[i+27], b[i+27]); sum += DO_MUL(a[i+28], b[i+28]); sum += DO_MUL(a[i+29], b[i+29]); sum += DO_MUL(a[i+30], b[i+30]); sum += DO_MUL(a[i+31], b[i+31]); x[j] = sum; b += MAT_BLK_SZ; } } // experiment with shorter int's static void muladd1_by_32_full(unsigned long *x, const unsigned int *a, const unsigned int *b) { for (long j = 0; j < MAT_BLK_SZ; j+=4) { unsigned long sum = x[j]; unsigned long sum_1 = x[j+1]; unsigned long sum_2 = x[j+2]; unsigned long sum_3 = x[j+3]; const unsigned int *b_1 = b+MAT_BLK_SZ; const unsigned int *b_2 = b+2*MAT_BLK_SZ; const unsigned int *b_3 = b+3*MAT_BLK_SZ; ONE_STEP_L(0); ONE_STEP_L(1); ONE_STEP_L(2); ONE_STEP_L(3); ONE_STEP_L(4); ONE_STEP_L(5); ONE_STEP_L(6); ONE_STEP_L(7); ONE_STEP_L(8); ONE_STEP_L(9); ONE_STEP_L(10); ONE_STEP_L(11); ONE_STEP_L(12); ONE_STEP_L(13); ONE_STEP_L(14); ONE_STEP_L(15); ONE_STEP_L(16); ONE_STEP_L(17); ONE_STEP_L(18); ONE_STEP_L(19); ONE_STEP_L(20); ONE_STEP_L(21); ONE_STEP_L(22); ONE_STEP_L(23); ONE_STEP_L(24); ONE_STEP_L(25); ONE_STEP_L(26); ONE_STEP_L(27); ONE_STEP_L(28); ONE_STEP_L(29); ONE_STEP_L(30); ONE_STEP_L(31); x[j] = sum; x[j+1] = sum_1; x[j+2] = sum_2; x[j+3] = sum_3; b += 4*MAT_BLK_SZ; } } static void muladd1_by_32_full_width(unsigned long *x, const unsigned int *a, const unsigned int *b, long width) { long j = 0; for (; j <= width-4; j+=4) { unsigned long sum = x[j]; unsigned long sum_1 = x[j+1]; unsigned long sum_2 = x[j+2]; unsigned long sum_3 = x[j+3]; const unsigned int *b_1 = b+MAT_BLK_SZ; const unsigned int *b_2 = b+2*MAT_BLK_SZ; const unsigned int *b_3 = b+3*MAT_BLK_SZ; ONE_STEP_L(0); ONE_STEP_L(1); ONE_STEP_L(2); ONE_STEP_L(3); ONE_STEP_L(4); ONE_STEP_L(5); ONE_STEP_L(6); ONE_STEP_L(7); ONE_STEP_L(8); ONE_STEP_L(9); ONE_STEP_L(10); ONE_STEP_L(11); ONE_STEP_L(12); ONE_STEP_L(13); ONE_STEP_L(14); ONE_STEP_L(15); ONE_STEP_L(16); ONE_STEP_L(17); ONE_STEP_L(18); ONE_STEP_L(19); ONE_STEP_L(20); ONE_STEP_L(21); ONE_STEP_L(22); ONE_STEP_L(23); ONE_STEP_L(24); ONE_STEP_L(25); ONE_STEP_L(26); ONE_STEP_L(27); ONE_STEP_L(28); ONE_STEP_L(29); ONE_STEP_L(30); ONE_STEP_L(31); x[j] = sum; x[j+1] = sum_1; x[j+2] = sum_2; x[j+3] = sum_3; b += 4*MAT_BLK_SZ; } for (; j < width; j++) { unsigned long sum = x[j]; long i = 0; sum += DO_MUL(a[i+0], b[i+0]); sum += DO_MUL(a[i+1], b[i+1]); sum += DO_MUL(a[i+2], b[i+2]); sum += DO_MUL(a[i+3], b[i+3]); sum += DO_MUL(a[i+4], b[i+4]); sum += DO_MUL(a[i+5], b[i+5]); sum += DO_MUL(a[i+6], b[i+6]); sum += DO_MUL(a[i+7], b[i+7]); sum += DO_MUL(a[i+8], b[i+8]); sum += DO_MUL(a[i+9], b[i+9]); sum += DO_MUL(a[i+10], b[i+10]); sum += DO_MUL(a[i+11], b[i+11]); sum += DO_MUL(a[i+12], b[i+12]); sum += DO_MUL(a[i+13], b[i+13]); sum += DO_MUL(a[i+14], b[i+14]); sum += DO_MUL(a[i+15], b[i+15]); sum += DO_MUL(a[i+16], b[i+16]); sum += DO_MUL(a[i+17], b[i+17]); sum += DO_MUL(a[i+18], b[i+18]); sum += DO_MUL(a[i+19], b[i+19]); sum += DO_MUL(a[i+20], b[i+20]); sum += DO_MUL(a[i+21], b[i+21]); sum += DO_MUL(a[i+22], b[i+22]); sum += DO_MUL(a[i+23], b[i+23]); sum += DO_MUL(a[i+24], b[i+24]); sum += DO_MUL(a[i+25], b[i+25]); sum += DO_MUL(a[i+26], b[i+26]); sum += DO_MUL(a[i+27], b[i+27]); sum += DO_MUL(a[i+28], b[i+28]); sum += DO_MUL(a[i+29], b[i+29]); sum += DO_MUL(a[i+30], b[i+30]); sum += DO_MUL(a[i+31], b[i+31]); x[j] = sum; b += MAT_BLK_SZ; } } #endif static inline void muladd_all_by_32(long first, long last, unsigned long *x, const unsigned int *a, const unsigned int *b, long n) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); } } static inline void muladd_all_by_32_width(long first, long last, unsigned long *x, const unsigned long *a, const unsigned long *b, long n, long width) { if (width == MAT_BLK_SZ) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); } } else { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, width); } else { for (long i = first; i < last; i++) muladd1_by_32_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, width); } } } static inline void muladd_all_by_32(long first, long last, unsigned long *x, const unsigned long *a, const unsigned long *b, long n) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); } } static inline void muladd_all_by_32_width(long first, long last, unsigned long *x, const unsigned int *a, const unsigned int *b, long n, long width) { if (width == MAT_BLK_SZ) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n); } } else { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, width); } else { for (long i = first; i < last; i++) muladd1_by_32_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, width); } } } #if (!defined(__INTEL_COMPILER) && (NTL_BITS_PER_INT >= NTL_BITS_PER_LONG/2)) // Something goes wrong with the Intel ICC (version 16.0.3) compiler // in this case. // It goes away with -O1, so I suspect it is a compiler bug. typedef unsigned int uhlong; #else typedef unsigned long uhlong; #endif // NOTE: the following code is hardcoded for MAT_BLK_SZ == 32. // Also, we special case NTL_BITS_PER_LONG-NTL_SP_NBITS > 2, which // allows us to accumulate all 32 products without additional carries. #if (NTL_BITS_PER_LONG-NTL_SP_NBITS > 2) static void muladd1_by_32(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { ll_type sum; ll_init(sum, x[j]); #if 0 for (long i = 0; i < n; i++) ll_imul_add(sum, a[i], b[i]); #else long i=0; for(; i <= n-8; i+= 8) { ll_imul_add(sum, a[i+0], b[i+0]); ll_imul_add(sum, a[i+1], b[i+1]); ll_imul_add(sum, a[i+2], b[i+2]); ll_imul_add(sum, a[i+3], b[i+3]); ll_imul_add(sum, a[i+4], b[i+4]); ll_imul_add(sum, a[i+5], b[i+5]); ll_imul_add(sum, a[i+6], b[i+6]); ll_imul_add(sum, a[i+7], b[i+7]); } for (; i < n; i++) ll_imul_add(sum, a[i], b[i]); #endif unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); else res = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } static void muladd1_by_32_width(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { ll_type sum; ll_init(sum, x[j]); #if 0 for (long i = 0; i < n; i++) ll_imul_add(sum, a[i], b[i]); #else long i=0; for(; i <= n-8; i+= 8) { ll_imul_add(sum, a[i+0], b[i+0]); ll_imul_add(sum, a[i+1], b[i+1]); ll_imul_add(sum, a[i+2], b[i+2]); ll_imul_add(sum, a[i+3], b[i+3]); ll_imul_add(sum, a[i+4], b[i+4]); ll_imul_add(sum, a[i+5], b[i+5]); ll_imul_add(sum, a[i+6], b[i+6]); ll_imul_add(sum, a[i+7], b[i+7]); } for (; i < n; i++) ll_imul_add(sum, a[i], b[i]); #endif unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); else res = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } #if 0 static void muladd1_by_32_full(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { ll_type sum; ll_init(sum, x[j]); ll_imul_add(sum, a[0], b[0]); ll_imul_add(sum, a[1], b[1]); ll_imul_add(sum, a[2], b[2]); ll_imul_add(sum, a[3], b[3]); ll_imul_add(sum, a[4], b[4]); ll_imul_add(sum, a[5], b[5]); ll_imul_add(sum, a[6], b[6]); ll_imul_add(sum, a[7], b[7]); ll_imul_add(sum, a[8], b[8]); ll_imul_add(sum, a[9], b[9]); ll_imul_add(sum, a[10], b[10]); ll_imul_add(sum, a[11], b[11]); ll_imul_add(sum, a[12], b[12]); ll_imul_add(sum, a[13], b[13]); ll_imul_add(sum, a[14], b[14]); ll_imul_add(sum, a[15], b[15]); ll_imul_add(sum, a[16], b[16]); ll_imul_add(sum, a[17], b[17]); ll_imul_add(sum, a[18], b[18]); ll_imul_add(sum, a[19], b[19]); ll_imul_add(sum, a[20], b[20]); ll_imul_add(sum, a[21], b[21]); ll_imul_add(sum, a[22], b[22]); ll_imul_add(sum, a[23], b[23]); ll_imul_add(sum, a[24], b[24]); ll_imul_add(sum, a[25], b[25]); ll_imul_add(sum, a[26], b[26]); ll_imul_add(sum, a[27], b[27]); ll_imul_add(sum, a[28], b[28]); ll_imul_add(sum, a[29], b[29]); ll_imul_add(sum, a[30], b[30]); ll_imul_add(sum, a[31], b[31]); unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); else res = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } static void muladd1_by_32_full_width(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { ll_type sum; ll_init(sum, x[j]); ll_imul_add(sum, a[0], b[0]); ll_imul_add(sum, a[1], b[1]); ll_imul_add(sum, a[2], b[2]); ll_imul_add(sum, a[3], b[3]); ll_imul_add(sum, a[4], b[4]); ll_imul_add(sum, a[5], b[5]); ll_imul_add(sum, a[6], b[6]); ll_imul_add(sum, a[7], b[7]); ll_imul_add(sum, a[8], b[8]); ll_imul_add(sum, a[9], b[9]); ll_imul_add(sum, a[10], b[10]); ll_imul_add(sum, a[11], b[11]); ll_imul_add(sum, a[12], b[12]); ll_imul_add(sum, a[13], b[13]); ll_imul_add(sum, a[14], b[14]); ll_imul_add(sum, a[15], b[15]); ll_imul_add(sum, a[16], b[16]); ll_imul_add(sum, a[17], b[17]); ll_imul_add(sum, a[18], b[18]); ll_imul_add(sum, a[19], b[19]); ll_imul_add(sum, a[20], b[20]); ll_imul_add(sum, a[21], b[21]); ll_imul_add(sum, a[22], b[22]); ll_imul_add(sum, a[23], b[23]); ll_imul_add(sum, a[24], b[24]); ll_imul_add(sum, a[25], b[25]); ll_imul_add(sum, a[26], b[26]); ll_imul_add(sum, a[27], b[27]); ll_imul_add(sum, a[28], b[28]); ll_imul_add(sum, a[29], b[29]); ll_imul_add(sum, a[30], b[30]); ll_imul_add(sum, a[31], b[31]); unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); else res = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } #elif 1 // This version is consistently fastest on tests on Sandybridge and Haswell #define ONE_STEP(i) \ ll_imul_add(sum, a[i], b[i]);\ ll_imul_add(sum_1, a[i], b_1[i]);\ ll_imul_add(sum_2, a[i], b_2[i]);\ ll_imul_add(sum_3, a[i], b_3[i]);\ void muladd1_by_32_full(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j+=4) { ll_type sum, sum_1, sum_2, sum_3; ll_init(sum, x[j]); ll_init(sum_1, x[j+1]); ll_init(sum_2, x[j+2]); ll_init(sum_3, x[j+3]); const long *b_1 = b+MAT_BLK_SZ; const long *b_2 = b+2*MAT_BLK_SZ; const long *b_3 = b+3*MAT_BLK_SZ; ONE_STEP(0); ONE_STEP(1); ONE_STEP(2); ONE_STEP(3); ONE_STEP(4); ONE_STEP(5); ONE_STEP(6); ONE_STEP(7); ONE_STEP(8); ONE_STEP(9); ONE_STEP(10); ONE_STEP(11); ONE_STEP(12); ONE_STEP(13); ONE_STEP(14); ONE_STEP(15); ONE_STEP(16); ONE_STEP(17); ONE_STEP(18); ONE_STEP(19); ONE_STEP(20); ONE_STEP(21); ONE_STEP(22); ONE_STEP(23); ONE_STEP(24); ONE_STEP(25); ONE_STEP(26); ONE_STEP(27); ONE_STEP(28); ONE_STEP(29); ONE_STEP(30); ONE_STEP(31); unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); unsigned long sum0_1 = ll_get_lo(sum_1); unsigned long sum1_1 = ll_get_hi(sum_1); unsigned long sum0_2 = ll_get_lo(sum_2); unsigned long sum1_2 = ll_get_hi(sum_2); unsigned long sum0_3 = ll_get_lo(sum_3); unsigned long sum1_3 = ll_get_hi(sum_3); if (ll_red_struct.nbits == NTL_SP_NBITS) { x[j] = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); x[j+1] = sp_ll_red_31_normalized(0, sum1_1, sum0_1, p, ll_red_struct); x[j+2] = sp_ll_red_31_normalized(0, sum1_2, sum0_2, p, ll_red_struct); x[j+3] = sp_ll_red_31_normalized(0, sum1_3, sum0_3, p, ll_red_struct); } else { x[j] = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j+1] = sp_ll_red_31(0, sum1_1, sum0_1, p, ll_red_struct); x[j+2] = sp_ll_red_31(0, sum1_2, sum0_2, p, ll_red_struct); x[j+3] = sp_ll_red_31(0, sum1_3, sum0_3, p, ll_red_struct); } b += 4*MAT_BLK_SZ; } } void muladd1_by_32_full_width(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct, long width) { long j = 0; for (; j <= width-4; j+=4) { ll_type sum, sum_1, sum_2, sum_3; ll_init(sum, x[j]); ll_init(sum_1, x[j+1]); ll_init(sum_2, x[j+2]); ll_init(sum_3, x[j+3]); const long *b_1 = b+MAT_BLK_SZ; const long *b_2 = b+2*MAT_BLK_SZ; const long *b_3 = b+3*MAT_BLK_SZ; ONE_STEP(0); ONE_STEP(1); ONE_STEP(2); ONE_STEP(3); ONE_STEP(4); ONE_STEP(5); ONE_STEP(6); ONE_STEP(7); ONE_STEP(8); ONE_STEP(9); ONE_STEP(10); ONE_STEP(11); ONE_STEP(12); ONE_STEP(13); ONE_STEP(14); ONE_STEP(15); ONE_STEP(16); ONE_STEP(17); ONE_STEP(18); ONE_STEP(19); ONE_STEP(20); ONE_STEP(21); ONE_STEP(22); ONE_STEP(23); ONE_STEP(24); ONE_STEP(25); ONE_STEP(26); ONE_STEP(27); ONE_STEP(28); ONE_STEP(29); ONE_STEP(30); ONE_STEP(31); unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); unsigned long sum0_1 = ll_get_lo(sum_1); unsigned long sum1_1 = ll_get_hi(sum_1); unsigned long sum0_2 = ll_get_lo(sum_2); unsigned long sum1_2 = ll_get_hi(sum_2); unsigned long sum0_3 = ll_get_lo(sum_3); unsigned long sum1_3 = ll_get_hi(sum_3); if (ll_red_struct.nbits == NTL_SP_NBITS) { x[j] = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); x[j+1] = sp_ll_red_31_normalized(0, sum1_1, sum0_1, p, ll_red_struct); x[j+2] = sp_ll_red_31_normalized(0, sum1_2, sum0_2, p, ll_red_struct); x[j+3] = sp_ll_red_31_normalized(0, sum1_3, sum0_3, p, ll_red_struct); } else { x[j] = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j+1] = sp_ll_red_31(0, sum1_1, sum0_1, p, ll_red_struct); x[j+2] = sp_ll_red_31(0, sum1_2, sum0_2, p, ll_red_struct); x[j+3] = sp_ll_red_31(0, sum1_3, sum0_3, p, ll_red_struct); } b += 4*MAT_BLK_SZ; } for (; j < width; j++) { ll_type sum; ll_init(sum, x[j]); ll_imul_add(sum, a[0], b[0]); ll_imul_add(sum, a[1], b[1]); ll_imul_add(sum, a[2], b[2]); ll_imul_add(sum, a[3], b[3]); ll_imul_add(sum, a[4], b[4]); ll_imul_add(sum, a[5], b[5]); ll_imul_add(sum, a[6], b[6]); ll_imul_add(sum, a[7], b[7]); ll_imul_add(sum, a[8], b[8]); ll_imul_add(sum, a[9], b[9]); ll_imul_add(sum, a[10], b[10]); ll_imul_add(sum, a[11], b[11]); ll_imul_add(sum, a[12], b[12]); ll_imul_add(sum, a[13], b[13]); ll_imul_add(sum, a[14], b[14]); ll_imul_add(sum, a[15], b[15]); ll_imul_add(sum, a[16], b[16]); ll_imul_add(sum, a[17], b[17]); ll_imul_add(sum, a[18], b[18]); ll_imul_add(sum, a[19], b[19]); ll_imul_add(sum, a[20], b[20]); ll_imul_add(sum, a[21], b[21]); ll_imul_add(sum, a[22], b[22]); ll_imul_add(sum, a[23], b[23]); ll_imul_add(sum, a[24], b[24]); ll_imul_add(sum, a[25], b[25]); ll_imul_add(sum, a[26], b[26]); ll_imul_add(sum, a[27], b[27]); ll_imul_add(sum, a[28], b[28]); ll_imul_add(sum, a[29], b[29]); ll_imul_add(sum, a[30], b[30]); ll_imul_add(sum, a[31], b[31]); unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(0, sum1, sum0, p, ll_red_struct); else res = sp_ll_red_31(0, sum1, sum0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } #endif #else static void muladd1_by_32(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { ll_type sum; ll_init(sum, x[j]); long i = 0; for (; i < n-16; i++) ll_imul_add(sum, a[i], b[i]); ll_type acc21; ll_init(acc21, ll_get_hi(sum)); unsigned long acc0 = ll_get_lo(sum); ll_init(sum, acc0); for (; i < n; i++) ll_imul_add(sum, a[i], b[i]); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); else res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } static void muladd1_by_32_width(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { ll_type sum; ll_init(sum, x[j]); long i = 0; for (; i < n-16; i++) ll_imul_add(sum, a[i], b[i]); ll_type acc21; ll_init(acc21, ll_get_hi(sum)); unsigned long acc0 = ll_get_lo(sum); ll_init(sum, acc0); for (; i < n; i++) ll_imul_add(sum, a[i], b[i]); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); else res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } static void muladd1_by_32_full(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { ll_type sum; ll_init(sum, x[j]); ll_imul_add(sum, a[0], b[0]); ll_imul_add(sum, a[1], b[1]); ll_imul_add(sum, a[2], b[2]); ll_imul_add(sum, a[3], b[3]); ll_imul_add(sum, a[4], b[4]); ll_imul_add(sum, a[5], b[5]); ll_imul_add(sum, a[6], b[6]); ll_imul_add(sum, a[7], b[7]); ll_imul_add(sum, a[8], b[8]); ll_imul_add(sum, a[9], b[9]); ll_imul_add(sum, a[10], b[10]); ll_imul_add(sum, a[11], b[11]); ll_imul_add(sum, a[12], b[12]); ll_imul_add(sum, a[13], b[13]); ll_imul_add(sum, a[14], b[14]); ll_imul_add(sum, a[15], b[15]); ll_type acc21; ll_init(acc21, ll_get_hi(sum)); unsigned long acc0 = ll_get_lo(sum); ll_init(sum, acc0); ll_imul_add(sum, a[16], b[16]); ll_imul_add(sum, a[17], b[17]); ll_imul_add(sum, a[18], b[18]); ll_imul_add(sum, a[19], b[19]); ll_imul_add(sum, a[20], b[20]); ll_imul_add(sum, a[21], b[21]); ll_imul_add(sum, a[22], b[22]); ll_imul_add(sum, a[23], b[23]); ll_imul_add(sum, a[24], b[24]); ll_imul_add(sum, a[25], b[25]); ll_imul_add(sum, a[26], b[26]); ll_imul_add(sum, a[27], b[27]); ll_imul_add(sum, a[28], b[28]); ll_imul_add(sum, a[29], b[29]); ll_imul_add(sum, a[30], b[30]); ll_imul_add(sum, a[31], b[31]); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); else res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } static void muladd1_by_32_full_width(long *x, const long *a, const long *b, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { ll_type sum; ll_init(sum, x[j]); ll_imul_add(sum, a[0], b[0]); ll_imul_add(sum, a[1], b[1]); ll_imul_add(sum, a[2], b[2]); ll_imul_add(sum, a[3], b[3]); ll_imul_add(sum, a[4], b[4]); ll_imul_add(sum, a[5], b[5]); ll_imul_add(sum, a[6], b[6]); ll_imul_add(sum, a[7], b[7]); ll_imul_add(sum, a[8], b[8]); ll_imul_add(sum, a[9], b[9]); ll_imul_add(sum, a[10], b[10]); ll_imul_add(sum, a[11], b[11]); ll_imul_add(sum, a[12], b[12]); ll_imul_add(sum, a[13], b[13]); ll_imul_add(sum, a[14], b[14]); ll_imul_add(sum, a[15], b[15]); ll_type acc21; ll_init(acc21, ll_get_hi(sum)); unsigned long acc0 = ll_get_lo(sum); ll_init(sum, acc0); ll_imul_add(sum, a[16], b[16]); ll_imul_add(sum, a[17], b[17]); ll_imul_add(sum, a[18], b[18]); ll_imul_add(sum, a[19], b[19]); ll_imul_add(sum, a[20], b[20]); ll_imul_add(sum, a[21], b[21]); ll_imul_add(sum, a[22], b[22]); ll_imul_add(sum, a[23], b[23]); ll_imul_add(sum, a[24], b[24]); ll_imul_add(sum, a[25], b[25]); ll_imul_add(sum, a[26], b[26]); ll_imul_add(sum, a[27], b[27]); ll_imul_add(sum, a[28], b[28]); ll_imul_add(sum, a[29], b[29]); ll_imul_add(sum, a[30], b[30]); ll_imul_add(sum, a[31], b[31]); acc0 = ll_get_lo(sum); ll_add(acc21, ll_get_hi(sum)); long res; if (ll_red_struct.nbits == NTL_SP_NBITS) res = sp_ll_red_31_normalized(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); else res = sp_ll_red_31(ll_get_hi(acc21), ll_get_lo(acc21), acc0, p, ll_red_struct); x[j] = res; b += MAT_BLK_SZ; } } #endif static void muladd1_by_32_half2(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { unsigned long sum[2]; sum[0] = x[j]; sum[1] = 0; long k=0; long i=0; for(; i <= n-16; i+= 16) { unsigned long lsum = a[i+0]*b[i+0]; lsum += a[i+1]*b[i+1]; lsum += a[i+2]*b[i+2]; lsum += a[i+3]*b[i+3]; lsum += a[i+4]*b[i+4]; lsum += a[i+5]*b[i+5]; lsum += a[i+6]*b[i+6]; lsum += a[i+7]*b[i+7]; lsum += a[i+8]*b[i+8]; lsum += a[i+9]*b[i+9]; lsum += a[i+10]*b[i+10]; lsum += a[i+11]*b[i+11]; lsum += a[i+12]*b[i+12]; lsum += a[i+13]*b[i+13]; lsum += a[i+14]*b[i+14]; lsum += a[i+15]*b[i+15]; sum[k++] += lsum; } if (i < n) { unsigned long lsum = a[i]*b[i]; for (i++; i < n; i++) lsum += a[i]*b[i]; sum[k++] += lsum; } long t0 = sp_ll_red_21(0, sum[0], p, ll_red_struct); long t1 = sp_ll_red_21(0, sum[1], p, ll_red_struct); x[j] = AddMod(t0, t1, p); b += MAT_BLK_SZ; } } static void muladd1_by_32_half2_width(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { unsigned long sum[2]; sum[0] = x[j]; sum[1] = 0; long k=0; long i=0; for(; i <= n-16; i+= 16) { unsigned long lsum = a[i+0]*b[i+0]; lsum += a[i+1]*b[i+1]; lsum += a[i+2]*b[i+2]; lsum += a[i+3]*b[i+3]; lsum += a[i+4]*b[i+4]; lsum += a[i+5]*b[i+5]; lsum += a[i+6]*b[i+6]; lsum += a[i+7]*b[i+7]; lsum += a[i+8]*b[i+8]; lsum += a[i+9]*b[i+9]; lsum += a[i+10]*b[i+10]; lsum += a[i+11]*b[i+11]; lsum += a[i+12]*b[i+12]; lsum += a[i+13]*b[i+13]; lsum += a[i+14]*b[i+14]; lsum += a[i+15]*b[i+15]; sum[k++] += lsum; } if (i < n) { unsigned long lsum = a[i]*b[i]; for (i++; i < n; i++) lsum += a[i]*b[i]; sum[k++] += lsum; } long t0 = sp_ll_red_21(0, sum[0], p, ll_red_struct); long t1 = sp_ll_red_21(0, sum[1], p, ll_red_struct); x[j] = AddMod(t0, t1, p); b += MAT_BLK_SZ; } } // NOTE: oddly, this is slightly faster than the half2 routine, which // I would have thought would be faster // DIRT: this assumes MAT_BLK_SZ < (1L << NTL_BITS_PER_LONG/2), // which will hold unconditionally for MAT_BLK_SZ < 2^16. static void muladd1_by_32_half1(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct) { for (long j = 0; j < MAT_BLK_SZ; j++) { ll_type sum; ll_init(sum, x[j]); long i=0; for(; i <= n-4; i+= 4) { unsigned long lsum = a[i+0]*b[i+0]; lsum += a[i+1]*b[i+1]; lsum += a[i+2]*b[i+2]; lsum += a[i+3]*b[i+3]; ll_add(sum, lsum); } if (i < n) { unsigned long lsum = a[i]*b[i]; for (i++; i < n; i++) lsum += a[i]*b[i]; ll_add(sum, lsum); } unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); x[j] = sp_ll_red_21(sum1, sum0, p, ll_red_struct); b += MAT_BLK_SZ; } } static void muladd1_by_32_half1_width(long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct, long width) { for (long j = 0; j < width; j++) { ll_type sum; ll_init(sum, x[j]); long i=0; for(; i <= n-4; i+= 4) { unsigned long lsum = a[i+0]*b[i+0]; lsum += a[i+1]*b[i+1]; lsum += a[i+2]*b[i+2]; lsum += a[i+3]*b[i+3]; ll_add(sum, lsum); } if (i < n) { unsigned long lsum = a[i]*b[i]; for (i++; i < n; i++) lsum += a[i]*b[i]; ll_add(sum, lsum); } unsigned long sum0 = ll_get_lo(sum); unsigned long sum1 = ll_get_hi(sum); x[j] = sp_ll_red_21(sum1, sum0, p, ll_red_struct); b += MAT_BLK_SZ; } } static inline void muladd_all_by_32(long first, long last, long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct) { if ((p-1) >= (1L << ((NTL_BITS_PER_LONG/2)-1))) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, p, ll_red_struct); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct); } } else { for (long i = first; i < last; i++) muladd1_by_32_half1(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct); } } static inline void muladd_all_by_32_width(long first, long last, long *x, const long *a, const long *b, long n, long p, sp_ll_reduce_struct ll_red_struct, long width) { if (width == MAT_BLK_SZ) { if ((p-1) >= (1L << ((NTL_BITS_PER_LONG/2)-1))) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, p, ll_red_struct); } else { for (long i = first; i < last; i++) muladd1_by_32(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct); } } else { for (long i = first; i < last; i++) muladd1_by_32_half1(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct); } } else { if ((p-1) >= (1L << ((NTL_BITS_PER_LONG/2)-1))) { if (n == MAT_BLK_SZ) { for (long i = first; i < last; i++) muladd1_by_32_full_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, p, ll_red_struct, width); } else { for (long i = first; i < last; i++) muladd1_by_32_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct, width); } } else { for (long i = first; i < last; i++) muladd1_by_32_half1_width(x + i*MAT_BLK_SZ, a + i*MAT_BLK_SZ, b, n, p, ll_red_struct, width); } } } #endif static inline void muladd_interval(long * NTL_RESTRICT x, long * NTL_RESTRICT y, long c, long n, long p, mulmod_t pinv) { mulmod_precon_t cpinv = PrepMulModPrecon(c, p, pinv); for (long i = 0; i < n; i++) { long t = MulModPrecon(y[i], c, p, cpinv); x[i] = AddMod(x[i], t, p); } } // ****************************************************************** // // General matrix multiplication code // // ****************************************************************** static void basic_mul(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n, first, last) { for (long i = first; i < last; i++) { long j, k; const zz_p* ap = &A[i][0]; zz_p *xp = &X[i][0]; for (j = 0; j < m; j++) xp[j].LoopHole() = 0; for (k = 0; k < l; k++) { long aa = rep(ap[k]); if (aa != 0) { const zz_p* bp = &B[k][0]; long T1; mulmod_precon_t aapinv = PrepMulModPrecon(aa, p, pinv); for (j = 0; j < m; j++) { T1 = MulModPrecon(rep(bp[j]), aa, p, aapinv); xp[j].LoopHole() = AddMod(rep(xp[j]), T1, p); } } } } } NTL_GEXEC_RANGE_END } #ifdef NTL_HAVE_LL_TYPE static void alt_mul_L(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); sp_reduce_struct red_struct = zz_p::red_struct(); long bound = InnerProd_L_bound(p); const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, m, first, last) { Vec B_col; B_col.SetLength(l); long *bp = B_col.elts(); long i, j, k; for (j = first; j < last; j++) { for (k = 0; k < l; k++) bp[k] = rep(B[k][j]); for (i = 0; i < n; i++) { const zz_p *ap = &A[i][0]; X[i][j].LoopHole() = InnerProd_L(bp, ap, l, p, red_struct, bound); } } } NTL_GEXEC_RANGE_END } static void alt_mul_LL(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, m, first, last) { Vec B_col; B_col.SetLength(l); long *bp = B_col.elts(); long i, j, k; for (j = first; j < last; j++) { for (k = 0; k < l; k++) bp[k] = rep(B[k][j]); for (i = 0; i < n; i++) { const zz_p *ap = &A[i][0]; X[i][j].LoopHole() = InnerProd_LL(bp, ap, l, p, ll_red_struct); } } } NTL_GEXEC_RANGE_END } #ifdef NTL_HAVE_AVX static void blk_mul_DD(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); sp_reduce_struct red_struct = zz_p::red_struct(); UniqueArray< AlignedArray > A_buf; long npanels = (l+MAT_BLK_SZ-1)/MAT_BLK_SZ; A_buf.SetLength(npanels); for (long kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); A_buf[panel].SetLength(n * MAT_BLK_SZ); double *abp = &A_buf[panel][0]; for (long i = 0; i < n; i++, abp += MAT_BLK_SZ) { const zz_p *ap1 = &A[i][0]; for (long k = kk; k < k_max; k++) { abp[k-kk] = rep(ap1[k]); } for (long k = k_max; k < kk+MAT_BLK_SZ; k++) { abp[k-kk] = 0; } } } long nxpanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, nxpanels, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) NTL_IMPORT(p) NTL_IMPORT(red_struct) AlignedArray B_rec; B_rec.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); double *brec = B_rec.get(); AlignedArray X_buf; X_buf.SetLength(n*MAT_BLK_SZ); double *xbp = X_buf.get(); long jj, kk; long i, j, k; long panel; long xpanel; for (xpanel = first, jj = first*MAT_BLK_SZ; xpanel < last; xpanel++, jj += MAT_BLK_SZ) { long j_max = min(jj+MAT_BLK_SZ, m); for (i = 0; i < n*MAT_BLK_SZ; i++) xbp[i] = 0; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); for (k = kk; k < k_max; k++) { const zz_p *bp = &B[k][0]; for (j = jj; j < j_max; j++) brec[(k-kk)*MAT_BLK_SZ+(j-jj)] = rep(bp[j]); for (j = j_max; j < jj+MAT_BLK_SZ; j++) brec[(k-kk)*MAT_BLK_SZ+(j-jj)] = 0; } if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; for (i = 0; i < n*MAT_BLK_SZ; i++) xbp[i] = rem((unsigned long)(long)xbp[i], p, red_struct); } red_count = red_count-MAT_BLK_SZ; const double *abp = &A_buf[panel][0]; muladd_all_by_32_width(0, n, xbp, abp, brec, k_max-kk, j_max-jj); } for (i = 0; i < n; i++) { zz_p *xp = &X[i][0]; for (j = jj; j < j_max; j++) xp[j].LoopHole() = rem((unsigned long)(long)xbp[i*MAT_BLK_SZ + (j-jj)], p, red_struct); } } NTL_GEXEC_RANGE_END } #endif static void blk_mul_LL(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); Vec< Vec > A_buf; Vec abufp; long npanels = (l+MAT_BLK_SZ-1)/MAT_BLK_SZ; A_buf.SetLength(npanels); abufp.SetLength(npanels); for (long kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); A_buf[panel].SetLength(n * MAT_BLK_SZ); long *abp = A_buf[panel].elts(); abufp[panel] = abp; for (long i = 0; i < n; i++, abp += MAT_BLK_SZ) { const zz_p *ap1 = &A[i][0]; for (long k = kk; k < k_max; k++) { abp[k-kk] = rep(ap1[k]); } for (long k = k_max; k < kk+MAT_BLK_SZ; k++) { abp[k-kk] = 0; } } } long nxpanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, nxpanels, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) NTL_IMPORT(p) NTL_IMPORT(ll_red_struct) UniqueArray B_rec; B_rec.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); long *brec = B_rec.get(); UniqueArray X_buf; X_buf.SetLength(n*MAT_BLK_SZ); long *xbp = X_buf.get(); long jj, kk; long i, j, k; long panel; long xpanel; for (xpanel = first, jj = first*MAT_BLK_SZ; xpanel < last; xpanel++, jj += MAT_BLK_SZ) { long j_max = min(jj+MAT_BLK_SZ, m); for (i = 0; i < n*MAT_BLK_SZ; i++) xbp[i] = 0; for (kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); // fill brec, transposed for (k = kk; k < k_max; k++) { const zz_p *bp = &B[k][0]; for (j = jj; j < j_max; j++) brec[(k-kk)+(j-jj)*MAT_BLK_SZ] = rep(bp[j]); for (j = j_max; j < jj+MAT_BLK_SZ; j++) brec[(k-kk)+(j-jj)*MAT_BLK_SZ] = 0; } const long *abp = abufp[panel]; muladd_all_by_32_width(0, n, xbp, abp, brec, k_max-kk, p, ll_red_struct, j_max-jj); } for (i = 0; i < n; i++) { zz_p *xp = &X[i][0]; for (j = jj; j < j_max; j++) xp[j].LoopHole() = xbp[i*MAT_BLK_SZ + (j-jj)]; } } NTL_GEXEC_RANGE_END } static void blk_mul_L(const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); long p = zz_p::modulus(); sp_reduce_struct red_struct = zz_p::red_struct(); Vec< Vec > A_buf; Vec abufp; long npanels = (l+MAT_BLK_SZ-1)/MAT_BLK_SZ; A_buf.SetLength(npanels); abufp.SetLength(npanels); for (long kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); A_buf[panel].SetLength(n * MAT_BLK_SZ); uhlong *abp = A_buf[panel].elts(); abufp[panel] = abp; for (long i = 0; i < n; i++, abp += MAT_BLK_SZ) { const zz_p *ap1 = &A[i][0]; for (long k = kk; k < k_max; k++) { abp[k-kk] = rep(ap1[k]); } for (long k = k_max; k < kk+MAT_BLK_SZ; k++) { abp[k-kk] = 0; } } } long nxpanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; const bool seq = double(n)*double(l)*double(m) < PAR_THRESH; NTL_GEXEC_RANGE(seq, nxpanels, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) NTL_IMPORT(p) NTL_IMPORT(red_struct) UniqueArray B_rec; B_rec.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); uhlong *brec = B_rec.get(); UniqueArray X_buf; X_buf.SetLength(n*MAT_BLK_SZ); unsigned long *xbp = X_buf.get(); long jj, kk; long i, j, k; long panel; long xpanel; for (xpanel = first, jj = first*MAT_BLK_SZ; xpanel < last; xpanel++, jj += MAT_BLK_SZ) { long j_max = min(jj+MAT_BLK_SZ, m); for (i = 0; i < n*MAT_BLK_SZ; i++) xbp[i] = 0; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (kk = 0, panel = 0; kk < l; kk += MAT_BLK_SZ, panel++) { long k_max = min(kk+MAT_BLK_SZ, l); // fill brec, transposed for (k = kk; k < k_max; k++) { const zz_p *bp = &B[k][0]; for (j = jj; j < j_max; j++) brec[(k-kk)+(j-jj)*MAT_BLK_SZ] = rep(bp[j]); for (j = j_max; j < jj+MAT_BLK_SZ; j++) brec[(k-kk)+(j-jj)*MAT_BLK_SZ] = 0; } if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; for (i = 0; i < n*MAT_BLK_SZ; i++) xbp[i] = rem(xbp[i], p, red_struct); } red_count = red_count-MAT_BLK_SZ; const uhlong *abp = abufp[panel]; muladd_all_by_32_width(0, n, xbp, abp, brec, k_max-kk, j_max-jj); } for (i = 0; i < n; i++) { zz_p *xp = &X[i][0]; for (j = jj; j < j_max; j++) xp[j].LoopHole() = rem(xbp[i*MAT_BLK_SZ + (j-jj)], p, red_struct); } } NTL_GEXEC_RANGE_END } #endif static void mul_base (const mat_window_zz_p& X, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (n == 0 || l == 0 || m == 0) { clear(X); return; } #ifndef NTL_HAVE_LL_TYPE basic_mul(X, A, B); #else long p = zz_p::modulus(); long V = MAT_BLK_SZ*4; #ifdef NTL_HAVE_AVX // experimentally, blk_mul_DD beats all the alternatives // if each dimension is at least 16 if (n >= 16 && l >= 16 && m >= 16 && p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("number too big"); if (NTL_OVERFLOW(l, MAT_BLK_SZ, 0)) ResourceError("number too big"); if (NTL_OVERFLOW(m, MAT_BLK_SZ, 0)) ResourceError("number too big"); //cerr << "blk_mul_DD\n"; blk_mul_DD(X, A, B); return; } #endif if (n < 32 || l < 32 || m < 32) { if (InnerProd_L_viable(l, p)) { //cerr << "alt_mul_L\n"; alt_mul_L(X, A, B); } else { //cerr << "alt_mul_LL\n"; alt_mul_LL(X, A, B); } } else { // Experimentally, the block versions are better when all dimensions // are at least 32 if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("number too big"); if (NTL_OVERFLOW(l, MAT_BLK_SZ, 0)) ResourceError("number too big"); if (NTL_OVERFLOW(m, MAT_BLK_SZ, 0)) ResourceError("number too big"); if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { //cerr << "blk_mul_L\n"; blk_mul_L(X, A, B); } else { //cerr << "blk_mul_LL\n"; blk_mul_LL(X, A, B); } } #endif } // The following implementation of Strassen is derived directly // from the implementation in FLINT (see http://www.flintlib.org), // although a number of details have changed. // The following copyright notice appears in the relevant // file, which can be obtained at // https://github.com/fredrik-johansson/flint2/blob/trunk/nmod_mat/mul_strassen.c // committed on April 26, 2016. /* Copyright (C) 2008, Martin Albrecht Copyright (C) 2008, 2009 William Hart. Copyright (C) 2010, Fredrik Johansson This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ void mul_strassen(const mat_window_zz_p& C, const const_mat_window_zz_p& A, const const_mat_window_zz_p& B) { long a, b, c; long anr, anc, bnr, bnc; a = A.NumRows(); b = A.NumCols(); c = B.NumCols(); bool use_DD = false; // this code determines if mul_base triggers blk_mul_DD, // in which case a higher crossover is used #if (defined(NTL_HAVE_LL_TYPE) && defined(NTL_HAVE_AVX)) { long V = MAT_BLK_SZ*4; long p = zz_p::modulus(); if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { use_DD = true; } } #endif long nt = AvailableThreads(); long xover; // now we set the crossover -- it is kind of a heauristic // mess based on nt and use_DD...I've run some tests to // make sure these settings are reasonable, but a more // rational approach would be preferable if (nt > 1) { if (use_DD || nt > 8192/(2*MAT_BLK_SZ)) xover = 8192; else xover = max(800, nt*2*MAT_BLK_SZ); } else { if (use_DD) xover = 800; else xover = 448; } if (a <= xover || b <= xover || c <= xover) { mul_base(C, A, B); return; } anr = a / 2; anc = b / 2; bnr = anc; bnc = c / 2; const_mat_window_zz_p A11(A, 0, 0, anr, anc); const_mat_window_zz_p A12(A, 0, anc, anr, 2*anc); const_mat_window_zz_p A21(A, anr, 0, 2*anr, anc); const_mat_window_zz_p A22(A, anr, anc, 2*anr, 2*anc); const_mat_window_zz_p B11(B, 0, 0, bnr, bnc); const_mat_window_zz_p B12(B, 0, bnc, bnr, 2*bnc); const_mat_window_zz_p B21(B, bnr, 0, 2*bnr, bnc); const_mat_window_zz_p B22(B, bnr, bnc, 2*bnr, 2*bnc); mat_window_zz_p C11(C, 0, 0, anr, bnc); mat_window_zz_p C12(C, 0, bnc, anr, 2*bnc); mat_window_zz_p C21(C, anr, 0, 2*anr, bnc); mat_window_zz_p C22(C, anr, bnc, 2*anr, 2*bnc); mat_zz_p X1_store; X1_store.SetDims(anr, max(bnc, anc)); mat_window_zz_p X1a(X1_store, 0, 0, anr, anc); mat_window_zz_p X1b(X1_store, 0, 0, anr, bnc); mat_zz_p X2; X2.SetDims(anc, bnc); /* See Jean-Guillaume Dumas, Clement Pernet, Wei Zhou; "Memory efficient scheduling of Strassen-Winograd's matrix multiplication algorithm"; http://arxiv.org/pdf/0707.2347v3 for reference on the used operation scheduling. */ sub(X1a, A11, A21); sub(X2, B22, B12); mul_strassen(C21, X1a, X2); add(X1a, A21, A22); sub(X2, B12, B11); mul_strassen(C22, X1a, X2); sub(X1a, X1a, A11); sub(X2, B22, X2); mul_strassen(C12, X1a, X2); sub(X1a, A12, X1a); mul_strassen(C11, X1a, B22); mul_strassen(X1b, A11, B11); add(C12, X1b, C12); add(C21, C12, C21); add(C12, C12, C22); add(C22, C21, C22); add(C12, C12, C11); sub(X2, X2, B21); mul_strassen(C11, A22, X2); X2.kill(); sub(C21, C21, C11); mul_strassen(C11, A12, B21); add(C11, X1b, C11); X1_store.kill(); if (c > 2*bnc) /* A by last col of B -> last col of C */ { const_mat_window_zz_p Bc(B, 0, 2*bnc, b, c); mat_window_zz_p Cc(C, 0, 2*bnc, a, c); mul_strassen(Cc, A, Bc); } if (a > 2*anr) /* last row of A by B -> last row of C */ { const_mat_window_zz_p Ar(A, 2*anr, 0, a, b); mat_window_zz_p Cr(C, 2*anr, 0, a, c); mul_strassen(Cr, Ar, B); } if (b > 2*anc) /* last col of A by last row of B -> C */ { const_mat_window_zz_p Ac(A, 0, 2*anc, 2*anr, b); const_mat_window_zz_p Br(B, 2*bnr, 0, b, 2*bnc); mat_window_zz_p Cb(C, 0, 0, 2*anr, 2*bnc); // Cb += Ac*Br mat_zz_p tmp; tmp.SetDims(Cb.NumRows(), Cb.NumCols()); mul_strassen(tmp, Ac, Br); add(Cb, Cb, tmp); } } static void mul_aux(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); if (n == 0 || l == 0 || m == 0) { clear(X); return; } mul_strassen(X, A, B); } void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { if (&X == &A || &X == &B) { mat_zz_p tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } // ****************************************************************** // // Matrix inversion code // // ****************************************************************** static long relaxed_InvModStatus(long& x, long a, long n, bool relax) { if (relax) { return InvModStatus(x, a, n); } else { x = InvMod(a, n); return 0; } } static void basic_inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } Mat M; conv(M, A); // scratch space Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); bool seq = n < PAR_THRESH_SQ; bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes long pivot = M[i][k]; if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, M[k][k], p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); long *y = &M[k][0]; for (long j = 0; j < n; j++) y[j] = MulModPrecon(y[j], t1, p, t1pinv); y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) long *y = &M[k][0]; for (long i = first; i < last; i++) { if (i == k) continue; // skip row k long *x = &M[i][0]; long t1 = x[k]; t1 = NegateMod(t1, p); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < n; j++) { long t2 = MulModPrecon(y[j], t1, p, t1pinv); x[j] = AddMod(x[j], t2, p); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { long *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) _ntl_swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) X[i][j].LoopHole() = M[i][j]; d.LoopHole() = det; } #ifdef NTL_HAVE_LL_TYPE static void alt_inv_L(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } Mat M; conv(M, A); // scractch space Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool seq = n < PAR_THRESH_SQ; bool pivoting = false; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (long k = 0; k < n; k++) { bool cleanup = false; if (red_count-1 < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-1; long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem(M[i][k], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); // t1*pinv; unsigned long *y = &M[k][0]; for (long j = 0; j < n; j++) { long t2 = rem(y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) NTL_IMPORT(red_struct) unsigned long *y = &M[k][0]; if (cleanup) { for (long i = first; i < last; i++) { if (i == k) continue; // skip row k: the data won't change, but it // technically is a race condition in a multi-theaded // execution unsigned long *x = &M[i][0]; for (long j = 0; j < n; j++) { x[j] = rem(x[j], p, red_struct); } } } for (long i = first; i < last; i++) { if (i == k) continue; // skip row k unsigned long *x = &M[i][0]; long t1 = rem(x[k], p, red_struct); t1 = NegateMod(t1, p); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i unsigned long ut1 = t1; long j; for (j = 0; j <= n-4; j+=4) { unsigned long xj0 = x[j+0] + DO_MUL(y[j+0], ut1); unsigned long xj1 = x[j+1] + DO_MUL(y[j+1], ut1); unsigned long xj2 = x[j+2] + DO_MUL(y[j+2], ut1); unsigned long xj3 = x[j+3] + DO_MUL(y[j+3], ut1); x[j+0] = xj0; x[j+1] = xj1; x[j+2] = xj2; x[j+3] = xj3; } for (; j < n; j++) { x[j] += DO_MUL(y[j], ut1); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { unsigned long *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) _ntl_swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) X[i][j].LoopHole() = rem(M[i][j], p, red_struct); d.LoopHole() = det; } #ifdef NTL_HAVE_AVX static void alt_inv_DD(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } Vec< AlignedArray > M; M.SetLength(n); for (long i = 0; i < n; i++) M[i].SetLength(n); for (long i = 0; i < n; i++) { for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); } Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool seq = n < PAR_THRESH_SQ; bool pivoting = false; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (long k = 0; k < n; k++) { bool cleanup = false; if (red_count-1 < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-1; long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem((unsigned long)(long)M[i][k], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); // t1*pinv; double *y = &M[k][0]; for (long j = 0; j < n; j++) { long t2 = rem((unsigned long)(long)y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) NTL_IMPORT(red_struct) double *y = &M[k][0]; if (cleanup) { for (long i = first; i < last; i++) { if (i == k) continue; // skip row k: the data won't change, but it // technically is a race condition in a multi-theaded // execution double *x = &M[i][0]; for (long j = 0; j < n; j++) { x[j] = rem((unsigned long)(long)x[j], p, red_struct); } } } for (long i = first; i < last; i++) { if (i == k) continue; // skip row k double *x = &M[i][0]; long t1 = rem((unsigned long)(long)x[k], p, red_struct); t1 = NegateMod(t1, p); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i double ut1 = t1; muladd_interval1(x, y, ut1, n); } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { double *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) _ntl_swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) X[i][j].LoopHole() = rem((unsigned long)(long)M[i][j], p, red_struct); d.LoopHole() = det; } #endif #ifdef NTL_HAVE_AVX static void blk_inv_DD(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< AlignedArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); double *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); double *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool seq = double(n)*double(n)*double(MAT_BLK_SZ) < PAR_THRESH; bool pivoting = false; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; double *kpanelp = &M[kpanel][0]; if (cleanup) { for (long r = 0; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem((unsigned long)(long)kpanelp[r], p, red_struct); } for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem((unsigned long)(long)kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } double *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k double *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { long t2 = rem((unsigned long)(long)y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k-kk] = pivot_inv; } for (long i = 0; i < n; i++) { if (i == k) continue; // skip row k double *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = rem((unsigned long)(long)x[k-kk], p, red_struct); t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i double ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ); } } // finished processing current kpanel // next, reduce and apply to all other kpanels for (long r = 0; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem((unsigned long)(long)kpanelp[r], p, red_struct); // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); NTL_GEXEC_RANGE(seq, npanels, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) AlignedArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); double *buf = &buf_store[0]; for (long jpanel = first; jpanel < last; jpanel++) { if (jpanel == kpanel) continue; double *jpanelp = &M[jpanel][0]; if (cleanup) { for (long r = 0; r < n*MAT_BLK_SZ; r++) jpanelp[r] = rem((unsigned long)(long)jpanelp[r], p, red_struct); } // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k double *pos_p = &jpanelp[pos*MAT_BLK_SZ]; double *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf for (long i = 0; i < (k_max-kk)*MAT_BLK_SZ; i++) buf[i] = rem((unsigned long)(long)jpanelp[kk*MAT_BLK_SZ+i], p, red_struct); // jpanel += kpanel*buf muladd_all_by_32(0, n, jpanelp, kpanelp, buf, k_max-kk); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (pivoting) { // pivot colums, using reverse swap sequence for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) { // swap columns pos and k double *x = &M[pos / MAT_BLK_SZ][pos % MAT_BLK_SZ]; double *y = &M[k / MAT_BLK_SZ][k % MAT_BLK_SZ]; for (long i = 0; i < n; i++) { _ntl_swap(x[i*MAT_BLK_SZ], y[i*MAT_BLK_SZ]); } } } } // copy panels into X X.SetDims(n, n); for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); double *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { zz_p *xp = X[i].elts() + jj; for (long j = jj; j < j_max; j++) xp[j-jj].LoopHole() = rem((unsigned long)(long)panelp[j-jj], p, red_struct); } } d.LoopHole() = det; } #endif static void blk_inv_L(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); unsigned long *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); unsigned long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool seq = double(n)*double(n)*double(MAT_BLK_SZ) < PAR_THRESH; bool pivoting = false; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; unsigned long *kpanelp = &M[kpanel][0]; if (cleanup) { for (long r = 0; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem(kpanelp[r], p, red_struct); } for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem(kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } unsigned long *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k unsigned long *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { long t2 = rem(y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k-kk] = pivot_inv; } for (long i = 0; i < n; i++) { if (i == k) continue; // skip row k unsigned long *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = rem(x[k-kk], p, red_struct); t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i unsigned long ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ); } } // finished processing current kpanel // next, reduce and apply to all other kpanels for (long r = 0; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem(kpanelp[r], p, red_struct); // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); NTL_GEXEC_RANGE(seq, npanels, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); unsigned long *buf = &buf_store[0]; for (long jpanel = first; jpanel < last; jpanel++) { if (jpanel == kpanel) continue; unsigned long *jpanelp = &M[jpanel][0]; if (cleanup) { for (long r = 0; r < n*MAT_BLK_SZ; r++) jpanelp[r] = rem(jpanelp[r], p, red_struct); } // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k unsigned long *pos_p = &jpanelp[pos*MAT_BLK_SZ]; unsigned long *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf // here, we transpose it for (long k = kk; k < k_max; k++) for (long j = 0; j < MAT_BLK_SZ; j++) buf[j*MAT_BLK_SZ + (k-kk)] = rem(jpanelp[k*MAT_BLK_SZ+j], p, red_struct); // jpanel += kpanel*buf muladd_all_by_32(0, n, jpanelp, kpanelp, buf, k_max-kk); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (pivoting) { // pivot colums, using reverse swap sequence for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) { // swap columns pos and k unsigned long *x = &M[pos / MAT_BLK_SZ][pos % MAT_BLK_SZ]; unsigned long *y = &M[k / MAT_BLK_SZ][k % MAT_BLK_SZ]; for (long i = 0; i < n; i++) { _ntl_swap(x[i*MAT_BLK_SZ], y[i*MAT_BLK_SZ]); } } } } // copy panels into X X.SetDims(n, n); for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); unsigned long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { zz_p *xp = X[i].elts() + jj; for (long j = jj; j < j_max; j++) xp[j-jj].LoopHole() = rem(panelp[j-jj], p, red_struct); } } d.LoopHole() = det; } static void blk_inv_LL(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too big"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); long *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); bool seq = double(n)*double(n)*double(MAT_BLK_SZ) < PAR_THRESH; bool pivoting = false; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); long *kpanelp = &M[kpanel][0]; for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = kpanelp[i*MAT_BLK_SZ+(k-kk)]; if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } long *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k long *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { y[j] = MulModPrecon(y[j], t1, p, t1pinv); } y[k-kk] = pivot_inv; } for (long i = 0; i < n; i++) { if (i == k) continue; // skip row k long *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = x[k-kk]; t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i long ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ, p, pinv); } } // finished processing current kpanel // next, reduce and apply to all other kpanels // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod(kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); NTL_GEXEC_RANGE(seq, npanels, first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(ll_red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); long *buf = &buf_store[0]; for (long jpanel = first; jpanel < last; jpanel++) { if (jpanel == kpanel) continue; long *jpanelp = &M[jpanel][0]; // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k long *pos_p = &jpanelp[pos*MAT_BLK_SZ]; long *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf // here, we transpose it for (long k = kk; k < k_max; k++) for (long j = 0; j < MAT_BLK_SZ; j++) buf[j*MAT_BLK_SZ + (k-kk)] = jpanelp[k*MAT_BLK_SZ+j]; // jpanel += kpanel*buf muladd_all_by_32(0, n, jpanelp, kpanelp, buf, k_max-kk, p, ll_red_struct); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod(kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (pivoting) { // pivot colums, using reverse swap sequence for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) { // swap columns pos and k long *x = &M[pos / MAT_BLK_SZ][pos % MAT_BLK_SZ]; long *y = &M[k / MAT_BLK_SZ][k % MAT_BLK_SZ]; for (long i = 0; i < n; i++) { _ntl_swap(x[i*MAT_BLK_SZ], y[i*MAT_BLK_SZ]); } } } } // copy panels into X X.SetDims(n, n); for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { zz_p *xp = X[i].elts() + jj; for (long j = jj; j < j_max; j++) xp[j-jj].LoopHole() = panelp[j-jj]; } } d.LoopHole() = det; } #endif void relaxed_inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); #ifndef NTL_HAVE_LL_TYPE basic_inv(d, X, A, relax); #else long p = zz_p::modulus(); if (n < 16) { //cerr << "basic_inv\n"; basic_inv(d, X, A, relax); } else if (n/MAT_BLK_SZ < 4) { long V = 64; #ifdef NTL_HAVE_AVX if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { //cerr << "alt_inv_DD\n"; alt_inv_DD(d, X, A, relax); } else #endif if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { //cerr << "alt_inv_L\n"; alt_inv_L(d, X, A, relax); } else { //cerr << "basic_inv\n"; basic_inv(d, X, A, relax); } } else { long V = 4*MAT_BLK_SZ; #ifdef NTL_HAVE_AVX if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { //cerr << "blk_inv_DD\n"; blk_inv_DD(d, X, A, relax); } else #endif if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { //cerr << "blk_inv_L\n"; blk_inv_L(d, X, A, relax); } else { //cerr << "blk_inv_LL\n"; blk_inv_LL(d, X, A, relax); } } #endif } // ****************************************************************** // // Triangularizing square matrices, with applications // to solving linear systems and computing determinants. // Should be about 3x faster than the matrix inverse // algorithms. // // ****************************************************************** static void basic_tri(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); // adjust if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); // adjust if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); // adjust if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); // adjust if (xp) xp->SetLength(0); return; } // adjust (several lines) // scratch space Mat M; if (!trans) { conv(M, A); } else { M.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); } Vec bv; if (bp) conv(bv, *bp); // end adjust Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes long pivot = M[i][k]; if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; // adjust if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, M[k][k], p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); long *y = &M[k][0]; // adjust for (long j = k+1; j < n; j++) y[j] = MulModPrecon(y[j], t1, p, t1pinv); // adjust // y[k] = pivot_inv; // adjust if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } // adjust bool seq = n-(k+1) < PAR_THRESH_SQ; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) long *y = &M[k][0]; // adjust for (long ii = first; ii < last; ii++) { long i = ii + k+1; long *x = &M[i][0]; long t1 = x[k]; t1 = NegateMod(t1, p); // adjust // x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); // adjust for (long j = k+1; j < n; j++) { long t2 = MulModPrecon(y[j], t1, p, t1pinv); x[j] = AddMod(x[j], t2, p); } // adjust if (bp) { long t2 = MulModPrecon(bv[k], t1, p, t1pinv); bv[i] = AddMod(bv[i], t2, p); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } // adjust if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; for (long j = i+1; j < n; j++) { long t2 = MulMod(rep(X[j]), M[i][j], p); t1 = AddMod(t1, t2, p); } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } #ifdef NTL_HAVE_LL_TYPE static void alt_tri_L(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); // adjust if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); // adjust if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); if (xp) xp->SetLength(0); return; } // scratch space Mat M; if (!trans) { conv(M, A); } else { M.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); } Vec bv; if (bp) conv(bv, *bp); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (long k = 0; k < n; k++) { bool cleanup = false; if (red_count-1 < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-1; long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem(M[i][k], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); // t1*pinv; unsigned long *y = &M[k][0]; for (long j = k+1; j < n; j++) { long t2 = rem(y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } bool seq = n-(k+1) < PAR_THRESH_SQ; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) NTL_IMPORT(red_struct) unsigned long *y = &M[k][0]; if (cleanup) { for (long ii = first; ii < last; ii++) { long i = ii + k+1; unsigned long *x = &M[i][0]; for (long j = k+1; j < n; j++) { x[j] = rem(x[j], p, red_struct); } } } for (long ii = first; ii < last; ii++) { long i = ii + k+1; unsigned long *x = &M[i][0]; long t1 = rem(x[k], p, red_struct); t1 = NegateMod(t1, p); if (t1 == 0) continue; // add t1 * row k to row i unsigned long ut1 = t1; long j; for (j = k+1; j <= n-4; j+=4) { unsigned long xj0 = x[j+0] + DO_MUL(y[j+0], ut1); unsigned long xj1 = x[j+1] + DO_MUL(y[j+1], ut1); unsigned long xj2 = x[j+2] + DO_MUL(y[j+2], ut1); unsigned long xj3 = x[j+3] + DO_MUL(y[j+3], ut1); x[j+0] = xj0; x[j+1] = xj1; x[j+2] = xj2; x[j+3] = xj3; } for (; j < n; j++) { x[j] += DO_MUL(y[j], ut1); } if (bp) { long t2 = MulMod(bv[k], t1, p); bv[i] = AddMod(bv[i], t2, p); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; for (long j = i+1; j < n; j++) { long t0 = rem(M[i][j], p, red_struct); long t2 = MulMod(rep(X[j]), t0, p); t1 = AddMod(t1, t2, p); } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } #ifdef NTL_HAVE_AVX static void alt_tri_DD(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); // adjust if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); // adjust if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); if (xp) xp->SetLength(0); return; } // scratch space Vec< AlignedArray > M; M.SetLength(n); for (long i = 0; i < n; i++) M[i].SetLength(n); if (!trans) { for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); } else { for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); } Vec bv; if (bp) conv(bv, *bp); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (long k = 0; k < n; k++) { bool cleanup = false; if (red_count-1 < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-1; long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem((unsigned long)(long)M[i][k], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); det = NegateMod(det, p); P[k] = pos; pivoting = true; if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); // t1*pinv; double *y = &M[k][0]; for (long j = k+1; j < n; j++) { long t2 = rem((unsigned long)(long)y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } bool seq = n-(k+1) < PAR_THRESH_SQ; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) NTL_IMPORT(red_struct) double *y = &M[k][0]; if (cleanup) { for (long ii = first; ii < last; ii++) { long i = ii + k+1; double *x = &M[i][0]; for (long j = k+1; j < n; j++) { x[j] = rem((unsigned long)(long)x[j], p, red_struct); } } } long align_boundary = min((((k+1)+(NTL_AVX_DBL_ALIGN-1))/NTL_AVX_DBL_ALIGN)*NTL_AVX_DBL_ALIGN, n); for (long ii = first; ii < last; ii++) { long i = ii + k+1; double *x = &M[i][0]; long t1 = rem((unsigned long)(long)x[k], p, red_struct); t1 = NegateMod(t1, p); if (t1 == 0) continue; // add t1 * row k to row i double ut1 = t1; for (long j = k+1; j < align_boundary; j++) x[j] += y[j]*ut1; muladd_interval1(x+align_boundary, y+align_boundary, ut1, n-align_boundary); if (bp) { long t2 = MulMod(bv[k], t1, p); bv[i] = AddMod(bv[i], t2, p); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; for (long j = i+1; j < n; j++) { long t0 = rem((unsigned long)(long)M[i][j], p, red_struct); long t2 = MulMod(rep(X[j]), t0, p); t1 = AddMod(t1, t2, p); } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } #endif #ifdef NTL_HAVE_AVX static void blk_tri_DD(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); if (xp) xp->SetLength(0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< AlignedArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); double *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } if (trans) { // copy A transposed into panels for (long i = 0; i < n; i++) { const zz_p *row = &A[i][0]; double *col = &M[i/MAT_BLK_SZ][i%MAT_BLK_SZ]; for (long j = 0; j < n; j++) col[j*MAT_BLK_SZ] = rep(row[j]); } } else { // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); double *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } } Vec bv; if (bp) conv(bv, *bp); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; double *kpanelp = &M[kpanel][0]; if (cleanup) { for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem((unsigned long)(long)kpanelp[r], p, red_struct); } for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem((unsigned long)(long)kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } double *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k double *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { long t2 = rem((unsigned long)(long)y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k-kk] = pivot_inv; if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } for (long i = kk; i < n; i++) { if (i == k) continue; // skip row k double *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = rem((unsigned long)(long)x[k-kk], p, red_struct); t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i double ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ); if (bp) { long t2 = MulMod(bv[k], t1, p); bv[i] = AddMod(bv[i], t2, p); } } } // finished processing current kpanel // next, reduce and apply to all other kpanels for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem((unsigned long)(long)kpanelp[r], p, red_struct); // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); bool seq = double(npanels-(kpanel+1))*double(n)*double(MAT_BLK_SZ)*double(MAT_BLK_SZ) < PAR_THRESH; NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) AlignedArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); double *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; double *jpanelp = &M[jpanel][0]; if (cleanup) { for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) jpanelp[r] = rem((unsigned long)(long)jpanelp[r], p, red_struct); } // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k double *pos_p = &jpanelp[pos*MAT_BLK_SZ]; double *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf for (long i = 0; i < (k_max-kk)*MAT_BLK_SZ; i++) buf[i] = rem((unsigned long)(long)jpanelp[kk*MAT_BLK_SZ+i], p, red_struct); // jpanel += kpanel*buf muladd_all_by_32(kk, n, jpanelp, kpanelp, buf, k_max-kk); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; long start_panel = ((i+1)+MAT_BLK_SZ-1)/MAT_BLK_SZ; for (long jj = MAT_BLK_SZ*start_panel, panel = start_panel; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); double *row = &M[panel][i*MAT_BLK_SZ]; for (long j = jj; j < j_max; j++) { long t0 = rem((unsigned long)(long)row[j-jj], p, red_struct); long t2 = MulMod(rep(X[j]), t0, p); t1 = AddMod(t1, t2, p); } } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } #endif static void blk_tri_L(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); if (xp) xp->SetLength(0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); unsigned long *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } if (trans) { // copy A transposed into panels for (long i = 0; i < n; i++) { const zz_p *row = &A[i][0]; unsigned long *col = &M[i/MAT_BLK_SZ][i%MAT_BLK_SZ]; for (long j = 0; j < n; j++) col[j*MAT_BLK_SZ] = rep(row[j]); } } else { // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); unsigned long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } } Vec bv; if (bp) conv(bv, *bp); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; unsigned long *kpanelp = &M[kpanel][0]; if (cleanup) { for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem(kpanelp[r], p, red_struct); } for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = rem(kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } unsigned long *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k unsigned long *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { long t2 = rem(y[j], p, red_struct); y[j] = MulModPrecon(t2, t1, p, t1pinv); } y[k-kk] = pivot_inv; if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } for (long i = kk; i < n; i++) { if (i == k) continue; // skip row k unsigned long *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = rem(x[k-kk], p, red_struct); t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i unsigned long ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ); if (bp) { long t2 = MulMod(bv[k], t1, p); bv[i] = AddMod(bv[i], t2, p); } } } // finished processing current kpanel // next, reduce and apply to all other kpanels for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) kpanelp[r] = rem(kpanelp[r], p, red_struct); // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); bool seq = double(npanels-(kpanel+1))*double(n)*double(MAT_BLK_SZ)*double(MAT_BLK_SZ) < PAR_THRESH; NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); unsigned long *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; unsigned long *jpanelp = &M[jpanel][0]; if (cleanup) { for (long r = kk*MAT_BLK_SZ; r < n*MAT_BLK_SZ; r++) jpanelp[r] = rem(jpanelp[r], p, red_struct); } // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k unsigned long *pos_p = &jpanelp[pos*MAT_BLK_SZ]; unsigned long *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf // here, we transpose it for (long k = kk; k < k_max; k++) for (long j = 0; j < MAT_BLK_SZ; j++) buf[j*MAT_BLK_SZ + (k-kk)] = rem(jpanelp[k*MAT_BLK_SZ+j], p, red_struct); // jpanel += kpanel*buf muladd_all_by_32(kk, n, jpanelp, kpanelp, buf, k_max-kk); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; long start_panel = ((i+1)+MAT_BLK_SZ-1)/MAT_BLK_SZ; for (long jj = MAT_BLK_SZ*start_panel, panel = start_panel; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); unsigned long *row = &M[panel][i*MAT_BLK_SZ]; for (long j = jj; j < j_max; j++) { long t0 = rem(row[j-jj], p, red_struct); long t2 = MulMod(rep(X[j]), t0, p); t1 = AddMod(t1, t2, p); } } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } static void blk_tri_LL(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("tri: nonsquare matrix"); if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); if (bp && !xp) LogicError("tri: bad args"); if (n == 0) { set(d); if (xp) xp->SetLength(0); return; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); long *panelp = &M[panel][0]; for (long r = 0; r < n*MAT_BLK_SZ; r++) panelp[r] = 0; } if (trans) { // copy A transposed into panels for (long i = 0; i < n; i++) { const zz_p *row = &A[i][0]; long *col = &M[i/MAT_BLK_SZ][i%MAT_BLK_SZ]; for (long j = 0; j < n; j++) col[j*MAT_BLK_SZ] = rep(row[j]); } } else { // copy A into panels for (long jj = 0, panel = 0; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } } Vec bv; if (bp) conv(bv, *bp); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations long det; det = 1; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); bool pivoting = false; for (long kk = 0, kpanel = 0; kk < n; kk += MAT_BLK_SZ, kpanel++) { long k_max = min(kk+MAT_BLK_SZ, n); long *kpanelp = &M[kpanel][0]; for (long k = kk; k < k_max; k++) { long pos = -1; long pivot; long pivot_inv; for (long i = k; i < n; i++) { // NOTE: by using InvModStatus, this code will work // for prime-powers as well as primes pivot = kpanelp[i*MAT_BLK_SZ+(k-kk)]; if (pivot != 0 && !relaxed_InvModStatus(pivot_inv, pivot, p, relax)) { pos = i; break; } } if (pos == -1) { clear(d); return; } long *y = &kpanelp[k*MAT_BLK_SZ]; if (k != pos) { // swap rows pos and k long *x = &kpanelp[pos*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); det = NegateMod(det, p); P[k] = pos; pivoting = true; if (bp) _ntl_swap(bv[pos], bv[k]); } det = MulMod(det, pivot, p); { // multiply row k by pivot_inv long t1 = pivot_inv; mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = 0; j < MAT_BLK_SZ; j++) { y[j] = MulModPrecon(y[j], t1, p, t1pinv); } y[k-kk] = pivot_inv; if (bp) bv[k] = MulModPrecon(bv[k], t1, p, t1pinv); } for (long i = kk; i < n; i++) { if (i == k) continue; // skip row k long *x = &kpanelp[i*MAT_BLK_SZ]; long t1 = x[k-kk]; t1 = NegateMod(t1, p); x[k-kk] = 0; if (t1 == 0) continue; // add t1 * row k to row i long ut1 = t1; muladd_interval(x, y, ut1, MAT_BLK_SZ, p, pinv); if (bp) { long t2 = MulMod(bv[k], t1, p); bv[i] = AddMod(bv[i], t2, p); } } } // finished processing current kpanel // next, reduce and apply to all other kpanels // special processing: subtract 1 off of diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = SubMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); bool seq = double(npanels-(kpanel+1))*double(n)*double(MAT_BLK_SZ)*double(MAT_BLK_SZ) < PAR_THRESH; NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(ll_red_struct) NTL_IMPORT(kpanel) NTL_IMPORT(kpanelp) NTL_IMPORT(kk) NTL_IMPORT(k_max) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); long *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; long *jpanelp = &M[jpanel][0]; // perform swaps for (long k = kk; k < k_max; k++) { long pos = P[k]; if (pos != k) { // swap rows pos and k long *pos_p = &jpanelp[pos*MAT_BLK_SZ]; long *k_p = &jpanelp[k*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], k_p[j]); } } // copy block number kpanel (the one on the diagonal) into buf // here, we transpose it for (long k = kk; k < k_max; k++) for (long j = 0; j < MAT_BLK_SZ; j++) buf[j*MAT_BLK_SZ + (k-kk)] = jpanelp[k*MAT_BLK_SZ+j]; // jpanel += kpanel*buf muladd_all_by_32(kk, n, jpanelp, kpanelp, buf, k_max-kk, p, ll_red_struct); } NTL_GEXEC_RANGE_END // special processing: add 1 back to the diangonal for (long k = kk; k < k_max; k++) kpanelp[k*MAT_BLK_SZ+(k-kk)] = AddMod((long)kpanelp[k*MAT_BLK_SZ+(k-kk)], 1, p); } if (bp) { xp->SetLength(n); zz_p *X = xp->elts(); for (long i = n-1; i >= 0; i--) { long t1 = 0; long start_panel = ((i+1)+MAT_BLK_SZ-1)/MAT_BLK_SZ; for (long jj = MAT_BLK_SZ*start_panel, panel = start_panel; jj < n; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, n); long *row = &M[panel][i*MAT_BLK_SZ]; for (long j = jj; j < j_max; j++) { long t0 = row[j-jj]; long t2 = MulMod(rep(X[j]), t0, p); t1 = AddMod(t1, t2, p); } } X[i].LoopHole() = SubMod(bv[i], t1, p); } } d.LoopHole() = det; } #endif static void tri(zz_p& d, const mat_zz_p& A, const vec_zz_p *bp, vec_zz_p *xp, bool trans, bool relax) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (bp && bp->length() != n) LogicError("tri: dimension mismatch"); if (bp && !xp) LogicError("tri: bad args"); #ifndef NTL_HAVE_LL_TYPE basic_tri(d, A, bp, xp, trans, relax); #else long p = zz_p::modulus(); if (n < 16) { //cerr << "basic_tri\n"; basic_tri(d, A, bp, xp, trans, relax); } else if (n/MAT_BLK_SZ < 4) { long V = 64; #ifdef NTL_HAVE_AVX if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { //cerr << "alt_tri_DD\n"; alt_tri_DD(d, A, bp, xp, trans, relax); } else #endif if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { //cerr << "alt_tri_L\n"; alt_tri_L(d, A, bp, xp, trans, relax); } else { //cerr << "basic_tri\n"; basic_tri(d, A, bp, xp, trans, relax); } } else { long V = 4*MAT_BLK_SZ; #ifdef NTL_HAVE_AVX if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { //cerr << "blk_tri_DD\n"; blk_tri_DD(d, A, bp, xp, trans, relax); } else #endif if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { //cerr << "blk_tri_L\n"; blk_tri_L(d, A, bp, xp, trans, relax); } else { //cerr << "blk_tri_LL\n"; blk_tri_LL(d, A, bp, xp, trans, relax); } } #endif } void relaxed_determinant(zz_p& d, const mat_zz_p& A, bool relax) { tri(d, A, 0, 0, false, relax); } void relaxed_solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b, bool relax) { tri(d, A, &b, &x, true, relax); } void relaxed_solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b, bool relax) { tri(d, A, &b, &x, false, relax); } // ****************************************************************** // // new image and kernel routines // // ****************************************************************** static long elim_basic(const mat_zz_p& A, mat_zz_p *im, mat_zz_p *ker, long w, bool full) { long n = A.NumRows(); long m = A.NumCols(); if (w < 0 || w > m) LogicError("elim: bad args"); // take care of corner cases if (n == 0) { if (im) im->SetDims(0, m); if (ker) ker->SetDims(0, 0); return 0; } if (w == 0) { if (im) { if (full) (*im) = A; else im->SetDims(0, m); } if (ker) ident(*ker, n); return 0; } Mat M; conv(M, A); Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations Vec pcol; pcol.SetLength(n); // pcol[i] records pivot columns for row i long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); bool pivoting = false; long r = 0; for (long k = 0; k < w; k++) { long pos = -1; long pivot_inv; for (long i = r; i < n; i++) { long pivot = M[i][k]; if (pivot != 0) { pivot_inv = InvMod(pivot, p); pos = i; break; } } if (pos == -1) continue; if (r != pos) { swap(M[pos], M[r]); P[r] = pos; pivoting = true; } bool seq = double(n-r)*double(m-k) < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(r+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(k) NTL_IMPORT(r) long *y = &M[r][0]; for (long ii = first; ii < last; ii++) { long i = ii + r+1; long *x = &M[i][0]; long t1 = x[k]; t1 = MulMod(t1, pivot_inv, p); t1 = NegateMod(t1, p); x[k] = t1; if (t1 == 0) continue; // add t1 * row r to row i mulmod_precon_t t1pinv = PrepMulModPrecon(t1, p, pinv); for (long j = k+1; j < m; j++) { long t2 = MulModPrecon(y[j], t1, p, t1pinv); x[j] = AddMod(x[j], t2, p); } } NTL_GEXEC_RANGE_END pcol[r] = k; r++; } if (im) { mat_zz_p& Im = *im;; if (full) Im.SetDims(n, m); else Im.SetDims(r, m); for (long i = 0; i < r; i++) { long pc = pcol[i]; for (long j = 0; j < pc; j++) Im[i][j].LoopHole() = 0; for (long j = pc; j < m; j++) Im[i][j].LoopHole() = M[i][j]; } if (full) { for (long i = r; i < n; i++) { for (long j = 0; j < w; j++) Im[i][j].LoopHole() = 0; for (long j = w; j < m; j++) Im[i][j].LoopHole() = M[i][j]; } } } if (ker) { if (n == r) { mat_zz_p& Ker = *ker; Ker.SetDims(n-r, n); } else { Mat colbuf; colbuf.SetDims(r, n); for (long k = 0; k < r; k++) { long pc = pcol[k]; for (long i = k+1; i < n; i++) colbuf[k][i] = M[i][pc]; } M.kill(); Mat X; X.SetDims(n-r, r); bool seq = double(n-r)*double(r)*double(r)/2 < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-r, first, last) NTL_IMPORT(p) NTL_IMPORT(r) for (long i = first; i < last; i++) { long *Xi = &X[i][0]; for (long k = r-1; k >= 0; k--) { long *cvecp = &colbuf[k][0]; long acc = cvecp[i+r]; for (long j = k+1; j < r; j++) { acc = AddMod( acc, MulMod(Xi[j], cvecp[j], p), p ); } Xi[k] = acc; } } NTL_GEXEC_RANGE_END mat_zz_p& Ker = *ker; Ker.SetDims(n-r, n); for (long i = 0; i < n-r; i++) { for (long j = 0; j < r; j++) Ker[i][j].LoopHole() = X[i][j]; for (long j = r; j < n; j++) Ker[i][j].LoopHole() = 0; Ker[i][r+i].LoopHole() = 1; } if (pivoting) { for (long i = 0; i < n-r; i++) { zz_p *x = Ker[i].elts(); for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } } } return r; } #ifdef NTL_HAVE_LL_TYPE #ifdef NTL_HAVE_AVX static inline void CopyBlock(double *dst_ptr, long dst_blk, const double *src_ptr, long src_blk, long src_limit) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = min(MAT_BLK_SZ, src_limit - src_row); for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; for (long i = nrows; i < MAT_BLK_SZ; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = 0; } static inline void CopyBlock(double *dst_ptr, long dst_blk, const double *src_ptr, long src_blk) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = MAT_BLK_SZ; for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; } static inline void SwapOneRow(double *panelp, long i, long pos) { double *pos_p = &panelp[pos*MAT_BLK_SZ]; double *i_p = &panelp[i*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], i_p[j]); } static inline void ApplySwaps(double *panelp, long start, long end, const Vec& P) { for (long i = start; i < end; i++) { long pos = P[i]; if (pos != i) SwapOneRow(panelp, i, pos); } } static inline void MulAddBlock(double *x, const double *y, const double *z) { // x += y*z muladd_all_by_32(0, MAT_BLK_SZ, x, y, z, MAT_BLK_SZ); } static long elim_blk_DD(const mat_zz_p& A, mat_zz_p *im, mat_zz_p *ker, long w, bool full) { long n = A.NumRows(); long m = A.NumCols(); if (w < 0 || w > m) LogicError("elim: bad args"); // take care of corner cases if (n == 0) { if (im) im->SetDims(0, m); if (ker) ker->SetDims(0, 0); return 0; } if (w == 0) { if (im) { if (full) (*im) = A; else im->SetDims(0, m); } if (ker) ident(*ker, n); return 0; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); if (NTL_OVERFLOW(m, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< AlignedArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); double *panelp = &M[panel][0]; for (long h = 0; h < n*MAT_BLK_SZ; h++) panelp[h] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < m; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, m); double *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } AlignedArray aux_panel_store; aux_panel_store.SetLength(n*MAT_BLK_SZ); double *aux_panel = &aux_panel_store[0]; AlignedArray buf_store1; buf_store1.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); double *buf1 = &buf_store1[0]; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations Vec pcol; pcol.SetLength(n); // pcol[i] records pivot columns for row i long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; long r = 0, rr = 0, k = 0, kk = 0; long rpanel = 0, kpanel = 0; while (k < w) { if (r > rr && ker) { // we have a panel from a previous iteration // we store enough of it to facilitate the kernel // computation later. At this point, we have // r == rr+INV_BLK_SIZE, and it suffices to store // rows [r..n) into M[rpanel], and this will not // overwrite anything useful in M[rpanel] double *panelp = &M[rpanel][0]; for (long h = r*MAT_BLK_SZ; h < n*MAT_BLK_SZ; h++) { panelp[h] = aux_panel[h]; } rpanel++; } rr = r; for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = 0; bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; for (; r < rr+MAT_BLK_SZ && k < w; k++) { // panel incomplete if (k == kk+MAT_BLK_SZ) { // start new kpanel kk = k; kpanel++; } double *kpanelp = &M[kpanel][0]; if (k == kk) { // a fresh kpanel -- special processing if (cleanup) { for (long h = 0; h < n*MAT_BLK_SZ; h++) kpanelp[h] = rem((unsigned long)(long)kpanelp[h], p, red_struct); } if (r > rr) { // apply current sequence of permutations ApplySwaps(kpanelp, rr, r, P); // clean aux_panel for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = rem((unsigned long)(long)aux_panel[h], p, red_struct); // copy rows [rr..r) of kpanel into buf1 for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf1[i] = rem((unsigned long)(long)kpanelp[rr*MAT_BLK_SZ+i], p, red_struct); // kpanel[rr..n) += aux_panel[rr..n)*buf1 muladd_all_by_32(rr, n, kpanelp, aux_panel, buf1, r-rr); } } long pos = -1; long pivot; long pivot_inv; for (long i = r; i < n; i++) { pivot = rem((unsigned long)(long)kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); kpanelp[i*MAT_BLK_SZ+(k-kk)] = pivot; if (pivot != 0) { pivot_inv = InvMod(pivot, p); pos = i; break; } } if (pos == -1) { continue; } double *y = &kpanelp[r*MAT_BLK_SZ]; double *y1 = &aux_panel[r*MAT_BLK_SZ]; if (r != pos) { // swap rows pos and r double *x = &kpanelp[pos*MAT_BLK_SZ]; double *x1 = &aux_panel[pos*MAT_BLK_SZ]; for (long j = k-kk; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); for (long j = 0; j < r-rr; j++) _ntl_swap(x1[j], y1[j]); P[r] = pos; pivoting = true; } // clean up row r of kpanel and aux_panel for (long j = k-kk; j < MAT_BLK_SZ; j++) y[j] = rem((unsigned long)(long)y[j], p, red_struct); for (long j = 0; j < r-rr; j++) y1[j] = rem((unsigned long)(long)y1[j], p, red_struct); // clear column for (long i = r+1; i < n; i++) { double *x = &kpanelp[i*MAT_BLK_SZ]; double *x1 = &aux_panel[i*MAT_BLK_SZ]; long t1 = rem((unsigned long)(long)x[k-kk], p, red_struct); t1 = MulMod(t1, pivot_inv, p); t1 = NegateMod(t1, p); x[k-kk] = 0; x1[r-rr] = t1; if (t1 == 0) continue; // add t1 * row r to row i double ut1 = t1; for (long j = k-kk+1; j < MAT_BLK_SZ; j++) x[j] += y[j]*ut1; for (long j = 0; j < r-rr; j++) x1[j] += y1[j]*ut1; } pcol[r] = k; r++; } if (r > rr) { // we have a panel // clean it up for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = rem((unsigned long)(long)aux_panel[h], p, red_struct); bool seq = double(npanels-(kpanel+1))*double(n-rr)*double(r-rr)*double(MAT_BLK_SZ) < PAR_THRESH; // apply aux_panel to remaining panels: [kpanel+1..npanels) NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(aux_panel) NTL_IMPORT(rr) NTL_IMPORT(r) AlignedArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); double *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; double *jpanelp = &M[jpanel][0]; if (cleanup) { for (long h = 0; h < n*MAT_BLK_SZ; h++) jpanelp[h] = rem((unsigned long)(long)jpanelp[h], p, red_struct); } // perform swaps ApplySwaps(jpanelp, rr, r, P); // copy rows [rr..r) of jpanel into buf for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf[i] = rem((unsigned long)(long)jpanelp[rr*MAT_BLK_SZ+i], p, red_struct); // jpanel[rr..n) += aux_panel[rr..n)*buf muladd_all_by_32(rr, n, jpanelp, aux_panel, buf, r-rr); } NTL_GEXEC_RANGE_END } } if (im) { mat_zz_p& Im = *im;; if (full) Im.SetDims(n, m); else Im.SetDims(r, m); for (long i = 0; i < r; i++) { long pc = pcol[i]; for (long j = 0; j < pc; j++) Im[i][j].LoopHole() = 0; for (long j = pc; j < m; j++) { double t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = rem((unsigned long)(long)t0, p, red_struct); } } if (full) { for (long i = r; i < n; i++) { for (long j = 0; j < w; j++) Im[i][j].LoopHole() = 0; for (long j = w; j < m; j++) { double t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = rem((unsigned long)(long)t0, p, red_struct); } } } } if (ker) { if (r == 0) { ident(*ker, n); return 0; } mat_zz_p& Ker = *ker; Ker.SetDims(n-r, n); if (r < n) { long start_block = r/MAT_BLK_SZ; long end_block = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; long vblocks = end_block-start_block; long hblocks = (r+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< AlignedArray > kerbuf; kerbuf.SetLength(vblocks); for (long i = 0; i < vblocks; i++) kerbuf[i].SetLength(hblocks*MAT_BLK_SZ*MAT_BLK_SZ); long colblocks = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; // if r > rr, we have a panel sitting in // aux_panel, which may or may not be a full panel double *initial_panel = 0; if (r > rr) { initial_panel = aux_panel; } else { initial_panel = &M[hblocks-1][0]; } for (long vb = start_block; vb < end_block; vb++) CopyBlock(&kerbuf[vb-start_block][0], hblocks-1, initial_panel, vb, n); for (long hb = hblocks-2; hb >= 0; hb--) { ApplySwaps(&M[hb][0], (hb+1)*MAT_BLK_SZ, r, P); for (long b = hb+1; b < end_block; b++) CopyBlock(&M[hb][0], b-1, &M[hb][0], b, n); } bool seq = double(n-r)*double(r)*double(r)/2 < PAR_THRESH; NTL_GEXEC_RANGE(seq, end_block-start_block, first, last) NTL_IMPORT(p) NTL_IMPORT(red_struct) NTL_IMPORT(hblocks) for (long index = first; index < last; index++) { long vb = index + start_block; double *kerbufp = &kerbuf[vb-start_block][0]; for (long hb = hblocks-2; hb >= 0; hb--) { double *colbuf = &M[hb][0]; double *acc = &kerbufp[hb*MAT_BLK_SZ*MAT_BLK_SZ]; CopyBlock(acc, 0, colbuf, vb-1); long red_trigger = (MAX_DBL_INT-(p-1))/((p-1)*(p-1)); long red_count = red_trigger; for (long b = hb+1; b < hblocks; b++) { if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; for (long h = 0; h < MAT_BLK_SZ*MAT_BLK_SZ; h++) acc[h] = rem((unsigned long)(long)acc[h], p, red_struct); } red_count = red_count-MAT_BLK_SZ; MulAddBlock(acc, &kerbufp[b*MAT_BLK_SZ*MAT_BLK_SZ], &colbuf[(b-1)*MAT_BLK_SZ*MAT_BLK_SZ]); } for (long h = 0; h < MAT_BLK_SZ*MAT_BLK_SZ; h++) acc[h] = rem((unsigned long)(long)acc[h], p, red_struct); } } NTL_GEXEC_RANGE_END for (long i = r; i < n; i++) { double *kerbufp = &kerbuf[(i/MAT_BLK_SZ)-start_block][0]; for (long j = 0; j < r; j++) { double t0 = kerbufp[(j/MAT_BLK_SZ)*MAT_BLK_SZ*MAT_BLK_SZ+ (i%MAT_BLK_SZ)*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Ker[i-r][j].LoopHole() = long(t0); } } for (long i = 0; i < n-r; i++) { for (long j = 0; j < n-r; j++) { Ker[i][j+r].LoopHole() = 0; } Ker[i][i+r].LoopHole() = 1; } if (pivoting) { for (long i = 0; i < n-r; i++) { zz_p *x = Ker[i].elts(); for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } } } return r; } #endif static inline void CopyBlock(unsigned long *dst_ptr, long dst_blk, const unsigned long *src_ptr, long src_blk, long src_limit) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = min(MAT_BLK_SZ, src_limit - src_row); for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; for (long i = nrows; i < MAT_BLK_SZ; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = 0; } static inline void CopyBlock(unsigned long *dst_ptr, long dst_blk, const unsigned long *src_ptr, long src_blk) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = MAT_BLK_SZ; for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; } static inline void TransposeBlock(unsigned long *dst_ptr, long dst_blk) { dst_ptr += dst_blk*MAT_BLK_SZ*MAT_BLK_SZ; for (long i = 0; i < MAT_BLK_SZ; i++) for (long j = 0; j < i; j++) _ntl_swap(dst_ptr[i*MAT_BLK_SZ+j], dst_ptr[i+j*MAT_BLK_SZ]); } static inline void SwapOneRow(unsigned long *panelp, long i, long pos) { unsigned long *pos_p = &panelp[pos*MAT_BLK_SZ]; unsigned long *i_p = &panelp[i*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], i_p[j]); } static inline void ApplySwaps(unsigned long *panelp, long start, long end, const Vec& P) { for (long i = start; i < end; i++) { long pos = P[i]; if (pos != i) SwapOneRow(panelp, i, pos); } } static inline void MulAddBlock(unsigned long *x, const unsigned long *y, const unsigned long *z) { // x += y*z muladd_all_by_32(0, MAT_BLK_SZ, x, y, z, MAT_BLK_SZ); } static long elim_blk_L(const mat_zz_p& A, mat_zz_p *im, mat_zz_p *ker, long w, bool full) { long n = A.NumRows(); long m = A.NumCols(); if (w < 0 || w > m) LogicError("elim: bad args"); // take care of corner cases if (n == 0) { if (im) im->SetDims(0, m); if (ker) ker->SetDims(0, 0); return 0; } if (w == 0) { if (im) { if (full) (*im) = A; else im->SetDims(0, m); } if (ker) ident(*ker, n); return 0; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); if (NTL_OVERFLOW(m, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); unsigned long *panelp = &M[panel][0]; for (long h = 0; h < n*MAT_BLK_SZ; h++) panelp[h] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < m; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, m); unsigned long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } UniqueArray aux_panel_store; aux_panel_store.SetLength(n*MAT_BLK_SZ); unsigned long *aux_panel = &aux_panel_store[0]; UniqueArray buf_store1; buf_store1.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); unsigned long *buf1 = &buf_store1[0]; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations Vec pcol; pcol.SetLength(n); // pcol[i] records pivot columns for row i long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_reduce_struct red_struct = zz_p::red_struct(); bool pivoting = false; unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; long r = 0, rr = 0, k = 0, kk = 0; long rpanel = 0, kpanel = 0; while (k < w) { if (r > rr && ker) { // we have a panel from a previous iteration // we store enough of it to facilitate the kernel // computation later. At this point, we have // r == rr+INV_BLK_SIZE, and it suffices to store // rows [r..n) into M[rpanel], and this will not // overwrite anything useful in M[rpanel] unsigned long *panelp = &M[rpanel][0]; for (long h = r*MAT_BLK_SZ; h < n*MAT_BLK_SZ; h++) { panelp[h] = aux_panel[h]; } rpanel++; } rr = r; for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = 0; bool cleanup = false; if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; cleanup = true; } red_count = red_count-MAT_BLK_SZ; for (; r < rr+MAT_BLK_SZ && k < w; k++) { // panel incomplete if (k == kk+MAT_BLK_SZ) { // start new kpanel kk = k; kpanel++; } unsigned long *kpanelp = &M[kpanel][0]; if (k == kk) { // a fresh kpanel -- special processing if (cleanup) { for (long h = 0; h < n*MAT_BLK_SZ; h++) kpanelp[h] = rem(kpanelp[h], p, red_struct); } if (r > rr) { // apply current sequence of permutations ApplySwaps(kpanelp, rr, r, P); // clean aux_panel for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = rem(aux_panel[h], p, red_struct); // copy rows [rr..r) of kpanel into buf1 for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf1[i] = rem(kpanelp[rr*MAT_BLK_SZ+i], p, red_struct); TransposeBlock(buf1, 0); // kpanel[rr..n) += aux_panel[rr..n)*buf1 muladd_all_by_32(rr, n, kpanelp, aux_panel, buf1, r-rr); } } long pos = -1; long pivot; long pivot_inv; for (long i = r; i < n; i++) { pivot = rem(kpanelp[i*MAT_BLK_SZ+(k-kk)], p, red_struct); kpanelp[i*MAT_BLK_SZ+(k-kk)] = pivot; if (pivot != 0) { pivot_inv = InvMod(pivot, p); pos = i; break; } } if (pos == -1) { continue; } unsigned long *y = &kpanelp[r*MAT_BLK_SZ]; unsigned long *y1 = &aux_panel[r*MAT_BLK_SZ]; if (r != pos) { // swap rows pos and r unsigned long *x = &kpanelp[pos*MAT_BLK_SZ]; unsigned long *x1 = &aux_panel[pos*MAT_BLK_SZ]; for (long j = k-kk; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); for (long j = 0; j < r-rr; j++) _ntl_swap(x1[j], y1[j]); P[r] = pos; pivoting = true; } // clean up row r of kpanel and aux_panel for (long j = k-kk; j < MAT_BLK_SZ; j++) y[j] = rem(y[j], p, red_struct); for (long j = 0; j < r-rr; j++) y1[j] = rem(y1[j], p, red_struct); // clear column for (long i = r+1; i < n; i++) { unsigned long *x = &kpanelp[i*MAT_BLK_SZ]; unsigned long *x1 = &aux_panel[i*MAT_BLK_SZ]; long t1 = rem(x[k-kk], p, red_struct); t1 = MulMod(t1, pivot_inv, p); t1 = NegateMod(t1, p); x[k-kk] = 0; x1[r-rr] = t1; if (t1 == 0) continue; // add t1 * row r to row i unsigned long ut1 = t1; for (long j = k-kk+1; j < MAT_BLK_SZ; j++) x[j] += y[j]*ut1; for (long j = 0; j < r-rr; j++) x1[j] += y1[j]*ut1; } pcol[r] = k; r++; } if (r > rr) { // we have a panel // clean it up for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = rem(aux_panel[h], p, red_struct); bool seq = double(npanels-(kpanel+1))*double(n-rr)*double(r-rr)*double(MAT_BLK_SZ) < PAR_THRESH; // apply aux_panel to remaining panels: [kpanel+1..npanels) NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(red_struct) NTL_IMPORT(aux_panel) NTL_IMPORT(rr) NTL_IMPORT(r) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); unsigned long *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; unsigned long *jpanelp = &M[jpanel][0]; if (cleanup) { for (long h = 0; h < n*MAT_BLK_SZ; h++) jpanelp[h] = rem(jpanelp[h], p, red_struct); } // perform swaps ApplySwaps(jpanelp, rr, r, P); // copy rows [rr..r) of jpanel into buf for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf[i] = rem(jpanelp[rr*MAT_BLK_SZ+i], p, red_struct); TransposeBlock(buf, 0); // jpanel[rr..n) += aux_panel[rr..n)*buf muladd_all_by_32(rr, n, jpanelp, aux_panel, buf, r-rr); } NTL_GEXEC_RANGE_END } } if (im) { mat_zz_p& Im = *im;; if (full) Im.SetDims(n, m); else Im.SetDims(r, m); for (long i = 0; i < r; i++) { long pc = pcol[i]; for (long j = 0; j < pc; j++) Im[i][j].LoopHole() = 0; for (long j = pc; j < m; j++) { unsigned long t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = rem(t0, p, red_struct); } } if (full) { for (long i = r; i < n; i++) { for (long j = 0; j < w; j++) Im[i][j].LoopHole() = 0; for (long j = w; j < m; j++) { unsigned long t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = rem(t0, p, red_struct); } } } } if (ker) { if (r == 0) { ident(*ker, n); return 0; } mat_zz_p& Ker = *ker; Ker.SetDims(n-r, n); if (r < n) { long start_block = r/MAT_BLK_SZ; long end_block = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; long vblocks = end_block-start_block; long hblocks = (r+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > kerbuf; kerbuf.SetLength(vblocks); for (long i = 0; i < vblocks; i++) kerbuf[i].SetLength(hblocks*MAT_BLK_SZ*MAT_BLK_SZ); long colblocks = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; // if r > rr, we have a panel sitting in // aux_panel, which may or may not be a full panel unsigned long *initial_panel = 0; if (r > rr) { initial_panel = aux_panel; } else { initial_panel = &M[hblocks-1][0]; } for (long vb = start_block; vb < end_block; vb++) CopyBlock(&kerbuf[vb-start_block][0], hblocks-1, initial_panel, vb, n); for (long hb = hblocks-2; hb >= 0; hb--) { ApplySwaps(&M[hb][0], (hb+1)*MAT_BLK_SZ, r, P); for (long b = hb+1; b < end_block; b++) { CopyBlock(&M[hb][0], b-1, &M[hb][0], b, n); TransposeBlock(&M[hb][0], b-1); } } bool seq = double(n-r)*double(r)*double(r)/2 < PAR_THRESH; NTL_GEXEC_RANGE(seq, end_block-start_block, first, last) NTL_IMPORT(p) NTL_IMPORT(red_struct) NTL_IMPORT(hblocks) for (long index = first; index < last; index++) { long vb = index + start_block; unsigned long *kerbufp = &kerbuf[vb-start_block][0]; for (long hb = hblocks-2; hb >= 0; hb--) { unsigned long *colbuf = &M[hb][0]; unsigned long *acc = &kerbufp[hb*MAT_BLK_SZ*MAT_BLK_SZ]; CopyBlock(acc, 0, colbuf, vb-1); TransposeBlock(acc, 0); unsigned long ured_trigger = (~(0UL)-cast_unsigned(p-1))/(cast_unsigned(p-1)*cast_unsigned(p-1)); // NOTE: corner case at p == 2: need unsigned long to prevent overflow long red_trigger = min(cast_unsigned(NTL_MAX_LONG), ured_trigger); long red_count = red_trigger; for (long b = hb+1; b < hblocks; b++) { if (red_count-MAT_BLK_SZ < 0) { red_count = red_trigger; for (long h = 0; h < MAT_BLK_SZ*MAT_BLK_SZ; h++) acc[h] = rem(acc[h], p, red_struct); } red_count = red_count-MAT_BLK_SZ; MulAddBlock(acc, &kerbufp[b*MAT_BLK_SZ*MAT_BLK_SZ], &colbuf[(b-1)*MAT_BLK_SZ*MAT_BLK_SZ]); } for (long h = 0; h < MAT_BLK_SZ*MAT_BLK_SZ; h++) acc[h] = rem(acc[h], p, red_struct); } } NTL_GEXEC_RANGE_END for (long i = r; i < n; i++) { unsigned long *kerbufp = &kerbuf[(i/MAT_BLK_SZ)-start_block][0]; for (long j = 0; j < r; j++) { unsigned long t0 = kerbufp[(j/MAT_BLK_SZ)*MAT_BLK_SZ*MAT_BLK_SZ+ (i%MAT_BLK_SZ)*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Ker[i-r][j].LoopHole() = long(t0); } } for (long i = 0; i < n-r; i++) { for (long j = 0; j < n-r; j++) { Ker[i][j+r].LoopHole() = 0; } Ker[i][i+r].LoopHole() = 1; } if (pivoting) { for (long i = 0; i < n-r; i++) { zz_p *x = Ker[i].elts(); for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } } } return r; } static inline void CopyBlock(long *dst_ptr, long dst_blk, const long *src_ptr, long src_blk, long src_limit) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = min(MAT_BLK_SZ, src_limit - src_row); for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; for (long i = nrows; i < MAT_BLK_SZ; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = 0; } static inline void CopyBlock(long *dst_ptr, long dst_blk, const long *src_ptr, long src_blk) { long src_row = src_blk*MAT_BLK_SZ; long dst_row = dst_blk*MAT_BLK_SZ; long nrows = MAT_BLK_SZ; for (long i = 0; i < nrows; i++) for (long j = 0; j < MAT_BLK_SZ; j++) dst_ptr[(dst_row + i)*MAT_BLK_SZ + j] = src_ptr[(src_row + i)*MAT_BLK_SZ + j]; } static inline void TransposeBlock(long *dst_ptr, long dst_blk) { dst_ptr += dst_blk*MAT_BLK_SZ*MAT_BLK_SZ; for (long i = 0; i < MAT_BLK_SZ; i++) for (long j = 0; j < i; j++) _ntl_swap(dst_ptr[i*MAT_BLK_SZ+j], dst_ptr[i+j*MAT_BLK_SZ]); } static inline void SwapOneRow(long *panelp, long i, long pos) { long *pos_p = &panelp[pos*MAT_BLK_SZ]; long *i_p = &panelp[i*MAT_BLK_SZ]; for (long j = 0; j < MAT_BLK_SZ; j++) _ntl_swap(pos_p[j], i_p[j]); } static inline void ApplySwaps(long *panelp, long start, long end, const Vec& P) { for (long i = start; i < end; i++) { long pos = P[i]; if (pos != i) SwapOneRow(panelp, i, pos); } } static inline void MulAddBlock(long *x, const long *y, const long *z, long p, sp_ll_reduce_struct ll_red_struct) { // x += y*z muladd_all_by_32(0, MAT_BLK_SZ, x, y, z, MAT_BLK_SZ, p, ll_red_struct); } static long elim_blk_LL(const mat_zz_p& A, mat_zz_p *im, mat_zz_p *ker, long w, bool full) { long n = A.NumRows(); long m = A.NumCols(); if (w < 0 || w > m) LogicError("elim: bad args"); // take care of corner cases if (n == 0) { if (im) im->SetDims(0, m); if (ker) ker->SetDims(0, 0); return 0; } if (w == 0) { if (im) { if (full) (*im) = A; else im->SetDims(0, m); } if (ker) ident(*ker, n); return 0; } if (NTL_OVERFLOW(n, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); if (NTL_OVERFLOW(m, MAT_BLK_SZ, 0)) ResourceError("dimension too large"); long npanels = (m+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > M; M.SetLength(npanels); for (long panel = 0; panel < npanels; panel++) { M[panel].SetLength(n*MAT_BLK_SZ); long *panelp = &M[panel][0]; for (long h = 0; h < n*MAT_BLK_SZ; h++) panelp[h] = 0; } // copy A into panels for (long jj = 0, panel = 0; jj < m; jj += MAT_BLK_SZ, panel++) { long j_max = min(jj+MAT_BLK_SZ, m); long *panelp = &M[panel][0]; for (long i = 0; i < n; i++, panelp += MAT_BLK_SZ) { const zz_p *ap = A[i].elts() + jj; for (long j = jj; j < j_max; j++) panelp[j-jj] = rep(ap[j-jj]); } } UniqueArray aux_panel_store; aux_panel_store.SetLength(n*MAT_BLK_SZ); long *aux_panel = &aux_panel_store[0]; UniqueArray buf_store1; buf_store1.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); long *buf1 = &buf_store1[0]; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations Vec pcol; pcol.SetLength(n); // pcol[i] records pivot columns for row i long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); sp_ll_reduce_struct ll_red_struct = zz_p::ll_red_struct(); bool pivoting = false; long r = 0, rr = 0, k = 0, kk = 0; long rpanel = 0, kpanel = 0; while (k < w) { if (r > rr && ker) { // we have a panel from a previous iteration // we store enough of it to facilitate the kernel // computation later. At this point, we have // r == rr+INV_BLK_SIZE, and it suffices to store // rows [r..n) into M[rpanel], and this will not // overwrite anything useful in M[rpanel] long *panelp = &M[rpanel][0]; for (long h = r*MAT_BLK_SZ; h < n*MAT_BLK_SZ; h++) { panelp[h] = aux_panel[h]; } rpanel++; } rr = r; for (long h = 0; h < n*MAT_BLK_SZ; h++) aux_panel[h] = 0; for (; r < rr+MAT_BLK_SZ && k < w; k++) { // panel incomplete if (k == kk+MAT_BLK_SZ) { // start new kpanel kk = k; kpanel++; } long *kpanelp = &M[kpanel][0]; if (k == kk) { // a fresh kpanel -- special processing if (r > rr) { // apply current sequence of permutations ApplySwaps(kpanelp, rr, r, P); // copy rows [rr..r) of kpanel into buf1 for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf1[i] = kpanelp[rr*MAT_BLK_SZ+i]; TransposeBlock(buf1, 0); // kpanel[rr..n) += aux_panel[rr..n)*buf1 muladd_all_by_32(rr, n, kpanelp, aux_panel, buf1, r-rr, p, ll_red_struct); } } long pos = -1; long pivot; long pivot_inv; for (long i = r; i < n; i++) { pivot = kpanelp[i*MAT_BLK_SZ+(k-kk)]; kpanelp[i*MAT_BLK_SZ+(k-kk)] = pivot; if (pivot != 0) { pivot_inv = InvMod(pivot, p); pos = i; break; } } if (pos == -1) { continue; } long *y = &kpanelp[r*MAT_BLK_SZ]; long *y1 = &aux_panel[r*MAT_BLK_SZ]; if (r != pos) { // swap rows pos and r long *x = &kpanelp[pos*MAT_BLK_SZ]; long *x1 = &aux_panel[pos*MAT_BLK_SZ]; for (long j = k-kk; j < MAT_BLK_SZ; j++) _ntl_swap(x[j], y[j]); for (long j = 0; j < r-rr; j++) _ntl_swap(x1[j], y1[j]); P[r] = pos; pivoting = true; } // clear column for (long i = r+1; i < n; i++) { long *x = &kpanelp[i*MAT_BLK_SZ]; long *x1 = &aux_panel[i*MAT_BLK_SZ]; long t1 = x[k-kk]; t1 = MulMod(t1, pivot_inv, p); t1 = NegateMod(t1, p); x[k-kk] = 0; x1[r-rr] = t1; if (t1 == 0) continue; // add t1 * row r to row i long ut1 = t1; mulmod_precon_t ut1_pinv = PrepMulModPrecon(ut1, p, pinv); for (long j = k-kk+1; j < MAT_BLK_SZ; j++) x[j] = AddMod(x[j], MulModPrecon(y[j], ut1, p, ut1_pinv), p); for (long j = 0; j < r-rr; j++) x1[j] = AddMod(x1[j], MulModPrecon(y1[j], ut1, p, ut1_pinv), p); } pcol[r] = k; r++; } if (r > rr) { // we have a panel bool seq = double(npanels-(kpanel+1))*double(n-rr)*double(r-rr)*double(MAT_BLK_SZ) < PAR_THRESH; // apply aux_panel to remaining panels: [kpanel+1..npanels) NTL_GEXEC_RANGE(seq, npanels-(kpanel+1), first, last) NTL_IMPORT(p) NTL_IMPORT(n) NTL_IMPORT(ll_red_struct) NTL_IMPORT(aux_panel) NTL_IMPORT(rr) NTL_IMPORT(r) UniqueArray buf_store; buf_store.SetLength(MAT_BLK_SZ*MAT_BLK_SZ); long *buf = &buf_store[0]; for (long index = first; index < last; index++) { long jpanel = index + kpanel+1; long *jpanelp = &M[jpanel][0]; // perform swaps ApplySwaps(jpanelp, rr, r, P); // copy rows [rr..r) of jpanel into buf for (long i = 0; i < (r-rr)*MAT_BLK_SZ; i++) buf[i] = jpanelp[rr*MAT_BLK_SZ+i]; TransposeBlock(buf, 0); // jpanel[rr..n) += aux_panel[rr..n)*buf muladd_all_by_32(rr, n, jpanelp, aux_panel, buf, r-rr, p, ll_red_struct); } NTL_GEXEC_RANGE_END } } if (im) { mat_zz_p& Im = *im;; if (full) Im.SetDims(n, m); else Im.SetDims(r, m); for (long i = 0; i < r; i++) { long pc = pcol[i]; for (long j = 0; j < pc; j++) Im[i][j].LoopHole() = 0; for (long j = pc; j < m; j++) { long t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = t0; } } if (full) { for (long i = r; i < n; i++) { for (long j = 0; j < w; j++) Im[i][j].LoopHole() = 0; for (long j = w; j < m; j++) { long t0 = M[j/MAT_BLK_SZ][i*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Im[i][j].LoopHole() = t0; } } } } if (ker) { if (r == 0) { ident(*ker, n); return 0; } mat_zz_p& Ker = *ker; Ker.SetDims(n-r, n); if (r < n) { long start_block = r/MAT_BLK_SZ; long end_block = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; long vblocks = end_block-start_block; long hblocks = (r+MAT_BLK_SZ-1)/MAT_BLK_SZ; Vec< UniqueArray > kerbuf; kerbuf.SetLength(vblocks); for (long i = 0; i < vblocks; i++) kerbuf[i].SetLength(hblocks*MAT_BLK_SZ*MAT_BLK_SZ); long colblocks = (n+MAT_BLK_SZ-1)/MAT_BLK_SZ; // if r > rr, we have a panel sitting in // aux_panel, which may or may not be a full panel long *initial_panel = 0; if (r > rr) { initial_panel = aux_panel; } else { initial_panel = &M[hblocks-1][0]; } for (long vb = start_block; vb < end_block; vb++) CopyBlock(&kerbuf[vb-start_block][0], hblocks-1, initial_panel, vb, n); for (long hb = hblocks-2; hb >= 0; hb--) { ApplySwaps(&M[hb][0], (hb+1)*MAT_BLK_SZ, r, P); for (long b = hb+1; b < end_block; b++) { CopyBlock(&M[hb][0], b-1, &M[hb][0], b, n); TransposeBlock(&M[hb][0], b-1); } } bool seq = double(n-r)*double(r)*double(r)/2 < PAR_THRESH; NTL_GEXEC_RANGE(seq, end_block-start_block, first, last) NTL_IMPORT(p) NTL_IMPORT(ll_red_struct) NTL_IMPORT(hblocks) for (long index = first; index < last; index++) { long vb = index + start_block; long *kerbufp = &kerbuf[vb-start_block][0]; for (long hb = hblocks-2; hb >= 0; hb--) { long *colbuf = &M[hb][0]; long *acc = &kerbufp[hb*MAT_BLK_SZ*MAT_BLK_SZ]; CopyBlock(acc, 0, colbuf, vb-1); TransposeBlock(acc, 0); for (long b = hb+1; b < hblocks; b++) { MulAddBlock(acc, &kerbufp[b*MAT_BLK_SZ*MAT_BLK_SZ], &colbuf[(b-1)*MAT_BLK_SZ*MAT_BLK_SZ], p, ll_red_struct); } } } NTL_GEXEC_RANGE_END for (long i = r; i < n; i++) { long *kerbufp = &kerbuf[(i/MAT_BLK_SZ)-start_block][0]; for (long j = 0; j < r; j++) { long t0 = kerbufp[(j/MAT_BLK_SZ)*MAT_BLK_SZ*MAT_BLK_SZ+ (i%MAT_BLK_SZ)*MAT_BLK_SZ+(j%MAT_BLK_SZ)]; Ker[i-r][j].LoopHole() = long(t0); } } for (long i = 0; i < n-r; i++) { for (long j = 0; j < n-r; j++) { Ker[i][j+r].LoopHole() = 0; } Ker[i][i+r].LoopHole() = 1; } if (pivoting) { for (long i = 0; i < n-r; i++) { zz_p *x = Ker[i].elts(); for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } } } return r; } #endif static long elim(const mat_zz_p& A, mat_zz_p *im, mat_zz_p *ker, long w, bool full) { long n = A.NumRows(); long m = A.NumCols(); if (w < 0 || w > m) LogicError("elim: bad args"); #ifndef NTL_HAVE_LL_TYPE return elim_basic(A, im, ker, w, full); #else long p = zz_p::modulus(); if (n/MAT_BLK_SZ < 4 || w/MAT_BLK_SZ < 4) { return elim_basic(A, im, ker, w, full); } else { long V = 4*MAT_BLK_SZ; #ifdef NTL_HAVE_AVX if (p-1 <= MAX_DBL_INT && V <= (MAX_DBL_INT-(p-1))/(p-1) && V*(p-1) <= (MAX_DBL_INT-(p-1))/(p-1)) { return elim_blk_DD(A, im, ker, w, full); } else #endif if (cast_unsigned(V) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1) && cast_unsigned(V)*cast_unsigned(p-1) <= (~(0UL)-cast_unsigned(p-1))/cast_unsigned(p-1)) { return elim_blk_L(A, im, ker, w, full); } else { return elim_blk_LL(A, im, ker, w, full); } } #endif } // ****************************************************************** // // High level interfaces // // ****************************************************************** long gauss(mat_zz_p& M, long w) { return elim(M, &M, 0, w, true); } long gauss(mat_zz_p& M) { return gauss(M, M.NumCols()); } void image(mat_zz_p& X, const mat_zz_p& A) { elim(A, &X, 0, A.NumCols(), false); } void kernel(mat_zz_p& X, const mat_zz_p& A) { elim(A, 0, &X, A.NumCols(), false); } // ****************************************************************** // // Operator/functional notation // // ****************************************************************** mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; add(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b) { mat_zz_p res; sub(res, a, b); NTL_OPT_RETURN(mat_zz_p, res); } mat_zz_p operator-(const mat_zz_p& a) { mat_zz_p res; negate(res, a); NTL_OPT_RETURN(mat_zz_p, res); } vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b) { vec_zz_p res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b) { vec_zz_p res; mul(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } #if 0 // for testing purposes void test_alt_mul_L(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { alt_mul_L(X, A, B); } void test_alt_mul_LL(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { alt_mul_LL(X, A, B); } void test_blk_mul_DD(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { blk_mul_DD(X, A, B); } void test_blk_mul_LL(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { blk_mul_LL(X, A, B); } void test_blk_mul_L(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { blk_mul_L(X, A, B); } void test_basic_mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B) { basic_mul(X, A, B); } #endif void random(mat_zz_p& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_lzz_pE.cpp0000644417616742025610000004701014064716022017556 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL // ========================================== #define PAR_THRESH (40000.0) static double zz_pE_SizeInWords() { return deg(zz_pE::modulus()); } static void mul_aux(Mat& X, const Mat& A, const Mat& B) { long n = A.NumRows(); long l = A.NumCols(); long m = B.NumCols(); if (l != B.NumRows()) LogicError("matrix mul: dimension mismatch"); X.SetDims(n, m); zz_pContext zz_p_context; zz_p_context.save(); zz_pEContext zz_pE_context; zz_pE_context.save(); double sz = zz_pE_SizeInWords(); bool seq = (double(n)*double(l)*double(m)*sz*sz < PAR_THRESH); NTL_GEXEC_RANGE(seq, m, first, last) NTL_IMPORT(n) NTL_IMPORT(l) NTL_IMPORT(m) zz_p_context.restore(); zz_pE_context.restore(); long i, j, k; zz_pX acc, tmp; Vec B_col; B_col.SetLength(l); for (j = first; j < last; j++) { for (k = 0; k < l; k++) B_col[k] = B[k][j]; for (i = 0; i < n; i++) { clear(acc); for (k = 0; k < l; k++) { mul(tmp, rep(A[i][k]), rep(B_col[k])); add(acc, acc, tmp); } conv(X[i][j], acc); } } NTL_GEXEC_RANGE_END } void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { if (&X == &A || &X == &B) { mat_zz_pE tmp; mul_aux(tmp, A, B); X = tmp; } else mul_aux(X, A, B); } void inv(zz_pE& d, Mat& X, const Mat& A) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } const zz_pXModulus& G = zz_pE::modulus(); zz_pX t1, t2; zz_pX pivot; zz_pX pivot_inv; Vec< Vec > M; // scratch space M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n); for (long j = 0; j < n; j++) { M[i][j].SetMaxLength(2*deg(G)-1); M[i][j] = rep(A[i][j]); } } zz_pX det; det = 1; Vec P; P.SetLength(n); for (long k = 0; k < n; k++) P[k] = k; // records swap operations zz_pContext zz_p_context; zz_p_context.save(); double sz = zz_pE_SizeInWords(); bool seq = double(n)*double(n)*sz*sz < PAR_THRESH; bool pivoting = false; for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(pivot, M[i][k], G); if (pivot != 0) { InvMod(pivot_inv, pivot, G); pos = i; break; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); P[k] = pos; pivoting = true; } MulMod(det, det, pivot, G); { // multiply row k by pivot_inv zz_pX *y = &M[k][0]; for (long j = 0; j < n; j++) { rem(t2, y[j], G); MulMod(y[j], t2, pivot_inv, G); } y[k] = pivot_inv; } NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(n) NTL_IMPORT(k) zz_p_context.restore(); zz_pX *y = &M[k][0]; zz_pX t1, t2; for (long i = first; i < last; i++) { if (i == k) continue; // skip row k zz_pX *x = &M[i][0]; rem(t1, x[k], G); negate(t1, t1); x[k] = 0; if (t1 == 0) continue; // add t1 * row k to row i for (long j = 0; j < n; j++) { mul(t2, y[j], t1); add(x[j], x[j], t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } if (pivoting) { // pivot colums, using reverse swap sequence for (long i = 0; i < n; i++) { zz_pX *x = &M[i][0]; for (long k = n-1; k >= 0; k--) { long pos = P[k]; if (pos != k) swap(x[pos], x[k]); } } } X.SetDims(n, n); for (long i = 0; i < n; i++) for (long j = 0; j < n; j++) conv(X[i][j], M[i][j]); conv(d, det); } static void solve_impl(zz_pE& d, Vec& X, const Mat& A, const Vec& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } zz_pX t1, t2; const zz_pXModulus& G = zz_pE::modulus(); Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n+1); for (long j = 0; j < n; j++) M[i][j].SetMaxLength(2*deg(G)-1); if (trans) for (long j = 0; j < n; j++) M[i][j] = rep(A[j][i]); else for (long j = 0; j < n; j++) M[i][j] = rep(A[i][j]); M[i][n] = rep(b[i]); } zz_pX det; set(det); zz_pContext zz_p_context; zz_p_context.save(); double sz = zz_pE_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j <= n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) zz_p_context.restore(); zz_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced zz_pX *x = M[i].elts() + (k+1); zz_pX *y = M[k].elts() + (k+1); for (long j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } X.SetLength(n); for (long i = n-1; i >= 0; i--) { clear(t1); for (long j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); } void solve(zz_pE& d, Vec& x, const Mat& A, const Vec& b) { solve_impl(d, x, A, b, true); } void solve(zz_pE& d, const Mat& A, Vec& x, const Vec& b) { solve_impl(d, x, A, b, false); } long gauss(Mat& M_in, long w) { zz_pX t1, t2; zz_pX piv; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); const zz_pXModulus& G = zz_pE::modulus(); Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(m); for (long j = 0; j < m; j++) { M[i][j].SetLength(2*deg(G)-1); M[i][j] = rep(M_in[i][j]); } } zz_pContext zz_p_context; zz_p_context.save(); double sz = zz_pE_SizeInWords(); long l = 0; for (long k = 0; k < w && l < n; k++) { long pos = -1; for (long i = l; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(piv, M[l][k], G); negate(piv, piv); for (long j = k+1; j < m; j++) { rem(M[l][j], M[l][j], G); } bool seq = double(n-(l+1))*double(m-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(l+1), first, last) NTL_IMPORT(m) NTL_IMPORT(k) NTL_IMPORT(l) zz_p_context.restore(); zz_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + l+1; // M[i] = M[i] + M[l]*M[i,k]*piv MulMod(t1, M[i][k], piv, G); clear(M[i][k]); zz_pX *x = M[i].elts() + (k+1); zz_pX *y = M[l].elts() + (k+1); for (long j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } NTL_GEXEC_RANGE_END l++; } } for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; } long gauss(Mat& M) { return gauss(M, M.NumCols()); } void image(Mat& X, const Mat& A) { Mat M; M = A; long r = gauss(M); M.SetDims(r, M.NumCols()); X = M; } void kernel(Mat& X, const Mat& A) { long m = A.NumRows(); long n = A.NumCols(); const zz_pXModulus& G = zz_pE::modulus(); Mat M; transpose(M, A); long r = gauss(M); if (r == 0) { ident(X, m); return; } X.SetDims(m-r, m); if (m-r == 0 || m == 0) return; Vec D; D.SetLength(m); for (long j = 0; j < m; j++) D[j] = -1; Vec inverses; inverses.SetLength(m); for (long i = 0, j = -1; i < r; i++) { do { j++; } while (IsZero(M[i][j])); D[j] = i; inv(inverses[j], M[i][j]); } zz_pEContext zz_pE_context; zz_pE_context.save(); zz_pContext zz_p_context; zz_p_context.save(); double sz = zz_pE_SizeInWords(); bool seq = double(m-r)*double(r)*double(r)*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, m-r, first, last) NTL_IMPORT(m) NTL_IMPORT(r) zz_p_context.restore(); zz_pE_context.restore(); zz_pX t1, t2; zz_pE T3; for (long k = first; k < last; k++) { Vec& v = X[k]; long pos = 0; for (long j = m-1; j >= 0; j--) { if (D[j] == -1) { if (pos == k) set(v[j]); else clear(v[j]); pos++; } else { long i = D[j]; clear(t1); for (long s = j+1; s < m; s++) { mul(t2, rep(v[s]), rep(M[i][s])); add(t1, t1, t2); } conv(T3, t1); mul(T3, T3, inverses[j]); negate(v[j], T3); } } } NTL_GEXEC_RANGE_END } void determinant(zz_pE& d, const Mat& M_in) { zz_pX t1, t2; const zz_pXModulus& G = zz_pE::modulus(); long n = M_in.NumRows(); if (M_in.NumCols() != n) LogicError("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } Vec< Vec > M; M.SetLength(n); for (long i = 0; i < n; i++) { M[i].SetLength(n); for (long j = 0; j < n; j++) { M[i][j].SetMaxLength(2*deg(G)-1); M[i][j] = rep(M_in[i][j]); } } zz_pX det; set(det); zz_pContext zz_p_context; zz_p_context.save(); double sz = zz_pE_SizeInWords(); for (long k = 0; k < n; k++) { long pos = -1; for (long i = k; i < n; i++) { rem(t1, M[i][k], G); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); negate(det, det); } MulMod(det, det, M[k][k], G); // make M[k, k] == -1 mod G, and make row k reduced InvMod(t1, M[k][k], G); negate(t1, t1); for (long j = k+1; j < n; j++) { rem(t2, M[k][j], G); MulMod(M[k][j], t2, t1, G); } bool seq = double(n-(k+1))*(n-(k+1))*sz*sz < PAR_THRESH; NTL_GEXEC_RANGE(seq, n-(k+1), first, last) NTL_IMPORT(n) NTL_IMPORT(k) zz_p_context.restore(); zz_pX t1, t2; for (long ii = first; ii < last; ii++) { long i = ii + k+1; // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced zz_pX *x = M[i].elts() + (k+1); zz_pX *y = M[k].elts() + (k+1); for (long j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } NTL_GEXEC_RANGE_END } else { clear(d); return; } } conv(d, det); } // ========================================== void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix add: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) add(X(i,j), A(i,j), B(i,j)); } void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B) { long n = A.NumRows(); long m = A.NumCols(); if (B.NumRows() != n || B.NumCols() != m) LogicError("matrix sub: dimension mismatch"); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) sub(X(i,j), A(i,j), B(i,j)); } void negate(mat_zz_pE& X, const mat_zz_pE& A) { long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) negate(X(i,j), A(i,j)); } static void mul_aux(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; zz_pX acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, rep(A(i,k)), rep(b(k))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b) { if (&b == &x || A.alias(x)) { vec_zz_pE tmp; mul_aux(tmp, A, b); x = tmp; } else mul_aux(x, A, b); } static void mul_aux(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; zz_pX acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, rep(a(k)), rep(B(k,i))); add(acc, acc, tmp); } conv(x(i), acc); } } void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B) { if (&a == &x) { vec_zz_pE tmp; mul_aux(tmp, a, B); x = tmp; } else mul_aux(x, a, B); } void ident(mat_zz_pE& X, long n) { X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) set(X(i, j)); else clear(X(i, j)); } long IsIdent(const mat_zz_pE& A, long n) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (!IsOne(A(i, j))) return 0; } return 1; } void transpose(mat_zz_pE& X, const mat_zz_pE& A) { long n = A.NumRows(); long m = A.NumCols(); long i, j; if (&X == & A) { if (n == m) for (i = 1; i <= n; i++) for (j = i+1; j <= n; j++) swap(X(i, j), X(j, i)); else { mat_zz_pE tmp; tmp.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) tmp(j, i) = A(i, j); X.kill(); X = tmp; } } else { X.SetDims(m, n); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) X(j, i) = A(i, j); } } void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b_in) { zz_pE b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b_in) { NTL_zz_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void mul(mat_zz_pE& X, const mat_zz_pE& A, long b_in) { NTL_zz_pRegister(b); b = b_in; long n = A.NumRows(); long m = A.NumCols(); X.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) mul(X[i][j], A[i][j], b); } void diag(mat_zz_pE& X, long n, const zz_pE& d_in) { zz_pE d = d_in; X.SetDims(n, n); long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i == j) X(i, j) = d; else clear(X(i, j)); } long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d) { if (A.NumRows() != n || A.NumCols() != n) return 0; long i, j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) if (i != j) { if (!IsZero(A(i, j))) return 0; } else { if (A(i, j) != d) return 0; } return 1; } long IsZero(const mat_zz_pE& a) { long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } void clear(mat_zz_pE& x) { long n = x.NumRows(); long i; for (i = 0; i < n; i++) clear(x[i]); } mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; add(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b) { mat_zz_pE res; sub(res, a, b); NTL_OPT_RETURN(mat_zz_pE, res); } mat_zz_pE operator-(const mat_zz_pE& a) { mat_zz_pE res; negate(res, a); NTL_OPT_RETURN(mat_zz_pE, res); } vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b) { vec_zz_pE res; mul_aux(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } void inv(mat_zz_pE& X, const mat_zz_pE& A) { zz_pE d; inv(d, X, A); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e) { if (A.NumRows() != A.NumCols()) LogicError("power: non-square matrix"); if (e == 0) { ident(X, A.NumRows()); return; } mat_zz_pE T1, T2; long i, k; k = NumBits(e); T1 = A; for (i = k-2; i >= 0; i--) { sqr(T2, T1); if (bit(e, i)) mul(T1, T2, A); else T1 = T2; } if (e < 0) inv(X, T1); else X = T1; } void random(mat_zz_pE& x, long n, long m) { x.SetDims(n, m); for (long i = 0; i < n; i++) random(x[i], m); } NTL_END_IMPL ntl-11.5.1/src/mat_poly_ZZ.cpp0000644417616742025610000000347614064716022017731 0ustar gid-shoupvpug-gid-shoupv#include #include #include NTL_START_IMPL static long CharPolyBound(const mat_ZZ& a) // This bound is computed via interpolation // through complex roots of unity. { long n = a.NumRows(); long i; ZZ res, t1, t2; set(res); for (i = 0; i < n; i++) { InnerProduct(t1, a[i], a[i]); abs(t2, a[i][i]); mul(t2, t2, 2); add(t2, t2, 1); add(t1, t1, t2); if (t1 > 1) { SqrRoot(t1, t1); add(t1, t1, 1); } mul(res, res, t1); } return NumBits(res); } void CharPoly(ZZX& gg, const mat_ZZ& a, long deterministic) { long n = a.NumRows(); if (a.NumCols() != n) LogicError("CharPoly: nonsquare matrix"); if (n == 0) { set(gg); return; } if (n == 1) { ZZ t; SetX(gg); negate(t, a(1, 1)); SetCoeff(gg, 0, t); return; } long bound = 2 + CharPolyBound(a); zz_pBak bak; bak.save(); ZZ_pBak bak1; bak1.save(); ZZX g; ZZ prod; clear(g); set(prod); long i; long instable = 1; long gp_cnt = 0; for (i = 0; ; i++) { if (NumBits(prod) > bound) break; if (!deterministic && !instable && bound > 1000 && NumBits(prod) < 0.25*bound) { long plen = 90 + NumBits(max(bound, MaxBits(g))); ZZ P; GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p A; ZZ_pX G; conv(A, a); CharPoly(G, A); if (CRT(g, prod, G)) instable = 1; else break; } zz_p::FFTInit(i); mat_zz_p A; zz_pX G; conv(A, a); CharPoly(G, A); instable = CRT(g, prod, G); } gg = g; bak.restore(); bak1.restore(); } NTL_END_IMPL ntl-11.5.1/src/mat_poly_ZZ_p.cpp0000644417616742025610000000277314064716022020247 0ustar gid-shoupvpug-gid-shoupv#include NTL_START_IMPL void CharPoly(ZZ_pX& f, const mat_ZZ_p& M) { long n = M.NumRows(); if (M.NumCols() != n) LogicError("CharPoly: nonsquare matrix"); if (n == 0) { set(f); return; } ZZ_p t; if (n == 1) { SetX(f); negate(t, M(1, 1)); SetCoeff(f, 0, t); return; } mat_ZZ_p H; H = M; long i, j, m; ZZ_p u, t1; for (m = 2; m <= n-1; m++) { i = m; while (i <= n && IsZero(H(i, m-1))) i++; if (i <= n) { t = H(i, m-1); if (i > m) { swap(H(i), H(m)); // swap columns i and m for (j = 1; j <= n; j++) swap(H(j, i), H(j, m)); } for (i = m+1; i <= n; i++) { div(u, H(i, m-1), t); for (j = m; j <= n; j++) { mul(t1, u, H(m, j)); sub(H(i, j), H(i, j), t1); } for (j = 1; j <= n; j++) { mul(t1, u, H(j, i)); add(H(j, m), H(j, m), t1); } } } } vec_ZZ_pX F; F.SetLength(n+1); ZZ_pX T; T.SetMaxLength(n); set(F[0]); for (m = 1; m <= n; m++) { LeftShift(F[m], F[m-1], 1); mul(T, F[m-1], H(m, m)); sub(F[m], F[m], T); set(t); for (i = 1; i <= m-1; i++) { mul(t, t, H(m-i+1, m-i)); mul(t1, t, H(m-i, m)); mul(T, F[m-i-1], t1); sub(F[m], F[m], T); } } f = F[n]; } NTL_END_IMPL ntl-11.5.1/src/mat_poly_lzz_p.cpp0000644417616742025610000000277314064716022020523 0ustar gid-shoupvpug-gid-shoupv#include NTL_START_IMPL void CharPoly(zz_pX& f, const mat_zz_p& M) { long n = M.NumRows(); if (M.NumCols() != n) LogicError("CharPoly: nonsquare matrix"); if (n == 0) { set(f); return; } zz_p t; if (n == 1) { SetX(f); negate(t, M(1, 1)); SetCoeff(f, 0, t); return; } mat_zz_p H; H = M; long i, j, m; zz_p u, t1; for (m = 2; m <= n-1; m++) { i = m; while (i <= n && IsZero(H(i, m-1))) i++; if (i <= n) { t = H(i, m-1); if (i > m) { swap(H(i), H(m)); // swap columns i and m for (j = 1; j <= n; j++) swap(H(j, i), H(j, m)); } for (i = m+1; i <= n; i++) { div(u, H(i, m-1), t); for (j = m; j <= n; j++) { mul(t1, u, H(m, j)); sub(H(i, j), H(i, j), t1); } for (j = 1; j <= n; j++) { mul(t1, u, H(j, i)); add(H(j, m), H(j, m), t1); } } } } vec_zz_pX F; F.SetLength(n+1); zz_pX T; T.SetMaxLength(n); set(F[0]); for (m = 1; m <= n; m++) { LeftShift(F[m], F[m-1], 1); mul(T, F[m-1], H(m, m)); sub(F[m], F[m], T); set(t); for (i = 1; i <= m-1; i++) { mul(t, t, H(m-i+1, m-i)); mul(t1, t, H(m-i, m)); mul(T, F[m-i-1], t1); sub(F[m], F[m], T); } } f = F[n]; } NTL_END_IMPL ntl-11.5.1/src/quad_float.cpp0000644417616742025610000001762314064716022017600 0ustar gid-shoupvpug-gid-shoupv // The quad_float module is derived from the doubledouble // library originally developed by Keith Briggs: // http://keithbriggs.info/doubledouble.html // I attach the original copyright notice. /* Copyright (C) 1997 Keith Martin Briggs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // The configure script tries to prevent this, but we // double check here. Note that while it is strongly // discouraged, other parts of NTL probably work even with // "fast math"; however, quad_float will definitely break. #if (defined(__GNUC__) && __FAST_MATH__) #error "do not compile quad_float.cpp with -ffast-math!!" #endif // The configure script should define NTL_FP_CONTRACT_OFF // for icc via the NOCONTRACT variable #ifdef NTL_FP_CONTRACT_OFF #pragma fp_contract(off) #endif #if 0 // The configure script should ensure that all NTL files // are compiled with --fp-model precise on icc. #ifdef __INTEL_COMPILER #pragma float_control(precise,on) #endif #endif #include #include NTL_START_IMPL #if (NTL_EXT_DOUBLE && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) #if (!defined(NTL_X86_FIX) && !defined(NTL_NO_X86_FIX)) #define NTL_X86_FIX #endif #endif #if (NTL_EXT_DOUBLE && !defined(NTL_X86_FIX)) #define DOUBLE volatile double #else #define DOUBLE double #endif #ifdef NTL_X86_FIX #define START_FIX \ unsigned short __old_cw, __new_cw; \ __asm__ volatile ("fnstcw %0":"=m" (__old_cw)::"memory"); \ __new_cw = (__old_cw & ~0x300) | 0x200; \ __asm__ volatile ("fldcw %0"::"m" (__new_cw):"memory"); #define END_FIX __asm__ volatile ("fldcw %0": :"m" (__old_cw)); // NOTE: "asm volatile" does not guarantee that the asm does // not move. However, the "memory" clobber makes these // memory barriers that cannot move past a load/store #define NO_INLINE __attribute__ ((noinline)) // to protect against LTO inlining which could break the memory // barriers in START_FIX and END_FIX. I've done some testing // on gcc, clang, and icc. The noinline attribute and the volatile // asm together should ensure that the function gets called // and doesn't get inlined during LTO. // That said, I wouln't really recommend applying LTO to NTL... // and especially to quad_float.cpp. // NOTE: gcc 8.1 seems a bit buggy: it warns when overloading a function // with different inline atrributes. Earlier versions are fine. // ICC and CLANG are fine. // NOTE: starting with gcc 8.1, there is a function attribute called // "noipa" which really does exactly what I want. It would also be useful // for ForceToMem, for example. #else #define START_FIX #define END_FIX #define NO_INLINE #endif NO_INLINE void quad_float_normalize(quad_float& z, const double& xhi, const double& xlo) { START_FIX DOUBLE u, v; u = xhi + xlo; v = xhi - u; v = v + xlo; z.hi = u; z.lo = v; END_FIX } NO_INLINE void quad_float_in_place_add(quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1; S = x.hi + y.hi; T = x.lo + y.lo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = y.hi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = y.lo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; x.hi = e; x.lo = f; END_FIX } NO_INLINE void quad_float_in_place_sub(quad_float& x, const quad_float& y ) { START_FIX DOUBLE H, h, T, t, S, s, e, f; DOUBLE t1, yhi, ylo; yhi = -y.hi; ylo = -y.lo; S = x.hi + yhi; T = x.lo + ylo; e = S - x.hi; f = T - x.lo; t1 = S-e; t1 = x.hi-t1; s = yhi-e; s = s + t1; t1 = T-f; t1 = x.lo-t1; t = ylo-f; t = t + t1; s = s + T; H = S + s; h = S - H; h = h + s; h = h + t; e = H + h; f = H - e; f = f + h; x.hi = e; x.lo = f; END_FIX } NO_INLINE void quad_float_in_place_negate(quad_float& x) { START_FIX DOUBLE xhi, xlo, u, v; xhi = -x.hi; xlo = -x.lo; // it is a good idea to renormalize here, just in case // the rounding rule depends on sign, and thus we will // maintain the "normal form" for quad_float's. u = xhi + xlo; v = xhi - u; v = v + xlo; x.hi = u; x.lo = v; END_FIX } #if (NTL_FMA_DETECTED && !defined(NTL_CONTRACTION_FIXED)) // The configure script should ensure that no FMA's are issued // fo most compilers (at least gcc, clang, and icc), but if not, // this is a last ditch effort to fix the problem (which seems to work). double quad_float_zero = 0; static inline double Protect(double x) { return x + quad_float_zero; } #else static inline double Protect(double x) { return x; } #endif NO_INLINE void quad_float_in_place_mul(quad_float& x,const quad_float& y ) { START_FIX DOUBLE hx, tx, hy, ty, C, c; DOUBLE t1, t2; C = Protect(NTL_QUAD_FLOAT_SPLIT*x.hi); hx = C-x.hi; c = Protect(NTL_QUAD_FLOAT_SPLIT*y.hi); hx = C-hx; tx = x.hi-hx; hy = c-y.hi; C = Protect(x.hi*y.hi); hy = c-hy; ty = y.hi-hy; // c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(x.hi*y.lo+x.lo*y.hi); t1 = Protect(hx*hy); t1 = t1-C; t2 = Protect(hx*ty); t1 = t1+t2; t2 = Protect(tx*hy); t1 = t1+t2; t2 = Protect(tx*ty); c = t1+t2; t1 = Protect(x.hi*y.lo); t2 = Protect(x.lo*y.hi); t1 = t1+t2; c = c + t1; hx = C+c; tx = C-hx; tx = tx+c; x.hi = hx; x.lo = tx; END_FIX } NO_INLINE void quad_float_in_place_div(quad_float& x, const quad_float& y ) { START_FIX DOUBLE hc, tc, hy, ty, C, c, U, u; DOUBLE t1; C = x.hi/y.hi; c = Protect(NTL_QUAD_FLOAT_SPLIT*C); hc = c-C; u = Protect(NTL_QUAD_FLOAT_SPLIT*y.hi); hc = c-hc; tc = C-hc; hy = u-y.hi; U = Protect(C * y.hi); hy = u-hy; ty = y.hi-hy; // u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; u = Protect(hc*hy); u = u-U; t1 = Protect(hc*ty); u = u+t1; t1 = Protect(tc*hy); u = u+t1; t1 = Protect(tc*ty); u = u+t1; // c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; c = x.hi-U; c = c-u; c = c+x.lo; t1 = Protect(C*y.lo); c = c - t1; c = c/y.hi; hy = C+c; ty = C-hy; ty = ty+c; x.hi = hy; x.lo = ty; END_FIX } NO_INLINE void quad_float_in_place_sqrt(quad_float& y, double& c_ref) { START_FIX DOUBLE c = c_ref; DOUBLE p,q,hx,tx,u,uu,cc; DOUBLE t1; p = Protect(NTL_QUAD_FLOAT_SPLIT*c); hx = (c-p); hx = hx+p; tx = c-hx; p = Protect(hx*hx); q = Protect(hx*tx); q = q+q; u = p+q; uu = p-u; uu = uu+q; t1 = Protect(tx*tx); uu = uu+t1; cc = y.hi-u; cc = cc-uu; cc = cc+y.lo; t1 = c+c; cc = cc/t1; hx = c+cc; tx = c-hx; tx = tx+cc; y.hi = hx; y.lo = tx; END_FIX } NO_INLINE void quad_float_PrecisionOK(long& res, const double& one) { START_FIX long k; DOUBLE l1 = one; DOUBLE lh = one/double(2); DOUBLE epsilon; DOUBLE fudge, oldfudge; epsilon = l1; fudge = l1+l1; k = 0; do { k++; epsilon = epsilon * lh; oldfudge = fudge; fudge = l1 + epsilon; } while (fudge > l1 && fudge < oldfudge); res = (k == NTL_DOUBLE_PRECISION); END_FIX } NTL_END_IMPL ntl-11.5.1/src/quad_float1.cpp0000644417616742025610000001657114064716022017662 0ustar gid-shoupvpug-gid-shoupv#include #include #include NTL_START_IMPL #if (NTL_BITS_PER_LONG >= NTL_DOUBLE_PRECISION) quad_float to_quad_float(long n) { double xhi, xlo; xhi = TrueDouble(n); // Because we are assuming 2's compliment integer // arithmetic, the following prevents long(xhi) from overflowing. if (n > 0) xlo = TrueDouble(n+long(-xhi)); else xlo = TrueDouble(n-long(xhi)); // renormalize...just to be safe quad_float z; quad_float_normalize(z, xhi, xlo); return z; } quad_float to_quad_float(unsigned long n) { double xhi, xlo, t; const double bnd = double(1L << (NTL_BITS_PER_LONG-2))*4.0; xhi = TrueDouble(n); if (xhi >= bnd) t = xhi - bnd; else t = xhi; // we use the "to_long" function here to be as portable as possible. long llo = to_long(n - (unsigned long)(t)); xlo = TrueDouble(llo); quad_float z; quad_float_normalize(z, xhi, xlo); return z; } #endif NTL_CHEAP_THREAD_LOCAL long quad_float::oprec = 10; void quad_float::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) ResourceError("quad_float: output precision too big"); oprec = p; } void power(quad_float& z, const quad_float& a, long e) { quad_float res, u; unsigned long k; if (e < 0) k = -((unsigned long) e); else k = e; res = 1.0; u = a; while (k) { if (k & 1) res = res * u; k = k >> 1; if (k) u = u * u; } if (e < 0) z = 1.0/res; else z = res; } void power2(quad_float& z, long e) { z.hi = _ntl_ldexp(1.0, e); z.lo = 0; } long to_long(const quad_float& x) { double fhi, flo; fhi = floor(x.hi); if (fhi == x.hi) flo = floor(x.lo); else flo = 0; // the following code helps to prevent unnecessary integer overflow, // and guarantees that to_long(to_quad_float(a)) == a, for all long a, // provided long's are not too wide. if (fhi > 0) return long(flo) - long(-fhi); else return long(fhi) + long(flo); } // This version of ZZ to quad_float coversion relies on the // precise rounding rules implemented by the ZZ to double conversion. void conv(quad_float& z, const ZZ& a) { double xhi, xlo; conv(xhi, a); if (!IsFinite(&xhi)) { z.hi = xhi; z.lo = 0; return; } NTL_ZZRegister(t); conv(t, xhi); sub(t, a, t); conv(xlo, t); quad_float_normalize(z, xhi, xlo); } void conv(ZZ& z, const quad_float& x) { NTL_ZZRegister(t1); NTL_ZZRegister(t2); NTL_ZZRegister(t3); double fhi, flo; fhi = floor(x.hi); if (fhi == x.hi) { flo = floor(x.lo); conv(t1, fhi); conv(t2, flo); add(z, t1, t2); } else conv(z, fhi); } ostream& operator<<(ostream& s, const quad_float& a) { quad_float aa = a; if (!IsFinite(&aa)) { s << "NaN"; return s; } RRPush push; RROutputPush opush; RR::SetPrecision(long(3.33*quad_float::oprec) + 10); RR::SetOutputPrecision(quad_float::oprec); NTL_TLS_LOCAL(RR, t); conv(t, a); s << t; return s; } istream& operator>>(istream& s, quad_float& x) { RRPush push; RR::SetPrecision(4*NTL_DOUBLE_PRECISION); NTL_TLS_LOCAL(RR, t); NTL_INPUT_CHECK_RET(s, s >> t); conv(x, t); return s; } void random(quad_float& x) { RRPush push; RR::SetPrecision(4*NTL_DOUBLE_PRECISION); NTL_TLS_LOCAL(RR, t); random(t); conv(x, t); } quad_float random_quad_float() { quad_float x; random(x); return x; } long IsFinite(quad_float *x) { return IsFinite(&x->hi) && IsFinite(&x->lo); } quad_float floor(const quad_float& x) { double fhi = floor(x.hi); if (fhi != x.hi) return quad_float(fhi, 0.0); else { double flo = floor(x.lo); quad_float z; quad_float_normalize(z, fhi, flo); return z; } } quad_float ceil(const quad_float& x) { return -floor(-x); } quad_float trunc(const quad_float& x) { if (x>=0.0) return floor(x); else return -floor(-x); } long compare(const quad_float& x, const quad_float& y) { if (x.hi > y.hi) return 1; else if (x.hi < y.hi) return -1; else if (x.lo > y.lo) return 1; else if (x.lo < y.lo) return -1; else return 0; } quad_float fabs(const quad_float& x) { if (x.hi>=0.0) return x; else return -x; } quad_float ldexp(const quad_float& x, long exp) { // x*2^exp double xhi, xlo; quad_float z; xhi = _ntl_ldexp(x.hi, exp); xlo = _ntl_ldexp(x.lo, exp); quad_float_normalize(z, xhi, xlo); return z; } quad_float exp(const quad_float& x) { // New version 97 Aug 05 /* ! Calculate a quadruple-precision exponential ! Method: ! x x.log2(e) nint[x.log2(e)] + frac[x.log2(e)] ! e = 2 = 2 ! ! iy fy ! = 2 . 2 ! Then ! fy y.loge(2) ! 2 = e ! ! Now y.loge(2) will be less than 0.3466 in absolute value. ! This is halved and a Pade aproximation is used to approximate e^x over ! the region (-0.1733, +0.1733). This approximation is then squared. */ if (x.hiDBL_MAX_10_EXP*2.302585092994045684017991) { ResourceError("exp(quad_float): overflow"); } static const quad_float Log2 = to_quad_float("0.6931471805599453094172321214581765680755"); // GLOBAL (assumes C++11 thread-safe init) quad_float y,temp,ysq,sum1,sum2; long iy; y=x/Log2; temp = floor(y+0.5); iy = to_long(temp); y=(y-temp)*Log2; y=ldexp(y,-1L); ysq=y*y; sum1=y*((((ysq+3960.0)*ysq+2162160.0)*ysq+302702400.0)*ysq+8821612800.0); sum2=(((90.0*ysq+110880.0)*ysq+30270240.0)*ysq+2075673600.0)*ysq+17643225600.0; /* ! sum2 + sum1 2.sum1 ! Now approximation = ----------- = 1 + ----------- = 1 + 2.temp ! sum2 - sum1 sum2 - sum1 ! ! Then (1 + 2.temp)^2 = 4.temp.(1 + temp) + 1 */ temp=sum1/(sum2-sum1); y=temp*(temp+1); y=ldexp(y,2L); return ldexp(y+1,iy); } quad_float log(const quad_float& t) { // Newton method. See Bailey, MPFUN if (t.hi <= 0.0) { ArithmeticError("log(quad_float): argument must be positive"); } quad_float s = to_quad_float(log(t.hi)); // NOTE: in case log yields excess precision, this assumes // that to_quad_float removes it quad_float e = exp(s); return s+(t-e)/e; // Newton step } quad_float sqrt(const quad_float& y) { if (y.hi < 0.0) ArithmeticError("quad_float: square root of negative number"); if (y.hi == 0.0) return quad_float(0.0,0.0); double c = TrueDouble(sqrt(y.hi)); // NOTE: we call TrueDouble, just in case sqrt yields excess precision quad_float yy = y; quad_float_in_place_sqrt(yy, c); return yy; } long operator> (const quad_float& x, const quad_float& y) { return (x.hi> y.hi) || (x.hi==y.hi && x.lo> y.lo); } long operator>=(const quad_float& x, const quad_float& y) { return (x.hi>y.hi) || (x.hi==y.hi && x.lo>=y.lo); } long operator< (const quad_float& x, const quad_float& y) { return (x.hi< y.hi) || (x.hi==y.hi && x.lo< y.lo); } long operator<=(const quad_float& x, const quad_float& y) { return (x.hi #include #include NTL_START_IMPL NTL_CHEAP_THREAD_LOCAL void (*ErrorCallback)() = 0; NTL_CHEAP_THREAD_LOCAL void (*ErrorMsgCallback)(const char *) = 0; void TerminalError(const char *s) { if (ErrorMsgCallback) (*ErrorMsgCallback)(s); else cerr << s << "\n"; if (ErrorCallback) (*ErrorCallback)(); abort(); } // The following implementation of CharToIntVal is completely portable. long CharToIntVal(long a) { switch (a) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; default: return -1; } } // The following implementation of IntValToChar is completely portable. char IntValToChar(long a) { switch (a) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; case 10: return 'a'; case 11: return 'b'; case 12: return 'c'; case 13: return 'd'; case 14: return 'e'; case 15: return 'f'; default: LogicError("IntValToChar: bad arg"); } return 0; // to supress warnings } long IsWhiteSpace(long a) { if (a > NTL_MAX_INT || a < NTL_MIN_INT) return 0; int b = (int) a; if (isspace(b)) return 1; else return 0; } long SkipWhiteSpace(istream& s) { long c; c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == EOF) return 0; else return 1; } long IsEOFChar(long c) { return c == EOF; } void PrintTime(ostream& s, double t) { long hh, mm, ss; ss = long(t + 0.5); hh = ss/3600; ss = ss - hh*3600; mm = ss/60; ss = ss - mm*60; if (hh > 0) s << hh << ":"; if (hh > 0 || mm > 0) { if (hh > 0 && mm < 10) s << "0"; s << mm << ":"; } if ((hh > 0 || mm > 0) && ss < 10) s << "0"; s << ss; } NTL_END_IMPL ntl-11.5.1/src/vec_GF2.cpp0000644417616742025610000002665014064716022016674 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL // FIXME: why do vec_GF2 and GF2X use different strategies for // keeping high order bits cleared? I don't think it matters // much, but it is strange. void vec_GF2::SetLength(long n) { long len = length(); if (n == len) return; if (n < 0) LogicError("negative length in vec_GF2::SetLength"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("vec_GF2::SetLength: excessive length"); if (fixed()) LogicError("SetLength: can't change this vector's length"); long wdlen = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; if (n < len) { // have to clear bits n..len-1 long q = n/NTL_BITS_PER_LONG; long p = n - q*NTL_BITS_PER_LONG; _ntl_ulong *x = rep.elts(); x[q] &= (1UL << p) - 1UL; long q1 = (len-1)/NTL_BITS_PER_LONG; long i; for (i = q+1; i <= q1; i++) x[i] = 0; _len = n; rep.QuickSetLength(wdlen); return; } long maxlen = MaxLength(); if (n <= maxlen) { _len = n; rep.QuickSetLength(wdlen); return; } long alloc = rep.MaxLength(); if (wdlen <= alloc) { _len = n; _maxlen = (n << 1); rep.QuickSetLength(wdlen); return; } // have to grow vector and initialize to zero rep.SetLength(wdlen); wdlen = rep.MaxLength(); // careful! rep.MaxLength() may exceed the // old value of wdlen...this is due to // the awkward semantics of WordVector. _ntl_ulong *x = rep.elts(); long i; for (i = alloc; i < wdlen; i++) x[i] = 0; _len = n; _maxlen = (n << 1); } void vec_GF2::SetLength(long n, GF2 a) { long old_len = length(); SetLength(n); if (!IsZero(a) && old_len < n) { long i; for (i = old_len; i < n; i++) put(i, a); } } vec_GF2& vec_GF2::operator=(const vec_GF2& a) { if (this == &a) return *this; long n = a.length(); SetLength(n); long wdlen = (n+NTL_BITS_PER_LONG-1)/NTL_BITS_PER_LONG; _ntl_ulong *x = rep.elts(); const _ntl_ulong *y = a.rep.elts(); long i; for (i = 0; i < wdlen; i++) x[i] = y[i]; return *this; } void vec_GF2::kill() { if (fixed()) LogicError("can't kill this vec_GF2"); rep.kill(); _len = _maxlen = 0; } void vec_GF2::SetMaxLength(long n) { long oldlen = length(); if (n > oldlen) { SetLength(n); SetLength(oldlen); } } void vec_GF2::FixLength(long n) { if (MaxLength() > 0 || fixed()) LogicError("can't fix this vector"); SetLength(n); _maxlen |= 1; } void vec_GF2::FixAtCurrentLength() { if (fixed()) return; if (length() != MaxLength()) LogicError("FixAtCurrentLength: can't fix this vector"); _maxlen |= 1; } void vec_GF2::swap(vec_GF2& y) { long xf = fixed(); long yf = y.fixed(); if (xf != yf || (xf && length() != y.length())) LogicError("swap: can't swap these vec_GF2s"); rep.swap(y.rep); _ntl_swap(_len, y._len); _ntl_swap(_maxlen, y._maxlen); } void vec_GF2::move(vec_GF2& y) { // special logic to get exception handling right if (&y == this) return; if (fixed() || y.fixed()) LogicError("move: can't move these vectors"); vec_GF2 tmp; tmp.swap(y); tmp.swap(*this); } void vec_GF2::append(GF2 a) { long n = length(); SetLength(n+1); put(n, a); } void vec_GF2::append(const vec_GF2& a) { long a_len = a.length(); long x_len = length(); if (a_len == 0) return; if (x_len == 0) { *this = a; return; } SetLength(x_len + a_len); // new bits are guaranteed zero ShiftAdd(rep.elts(), a.rep.elts(), a.rep.length(), x_len); } long operator==(const vec_GF2& a, const vec_GF2& b) { return a.length() == b.length() && a.rep == b.rep; } istream & operator>>(istream& s, vec_GF2& a) { NTL_ZZRegister(ival); long c; if (!s) NTL_INPUT_ERROR(s, "bad vec_GF2 input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { NTL_INPUT_ERROR(s, "bad vec_GF2 input"); } vec_GF2 ibuf; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && c != EOF) { if (!(s >> ival)) NTL_INPUT_ERROR(s, "bad vec_GF2 input"); append(ibuf, to_GF2(ival)); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (c == EOF) NTL_INPUT_ERROR(s, "bad vec_GF2 input"); s.get(); a = ibuf; return s; } ostream& operator<<(ostream& s, const vec_GF2& a) { long i, n; GF2 c; n = a.length(); s << '['; for (i = 0; i < n; i++) { c = a.get(i); if (c == 0) s << "0"; else s << "1"; if (i < n-1) s << " "; } s << ']'; return s; } // math operations: void mul(vec_GF2& x, const vec_GF2& a, GF2 b) { x = a; if (b == 0) clear(x); } void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b) { long blen = a.length(); if (b.length() != blen) LogicError("vec_GF2 add: length mismatch"); x.SetLength(blen); long wlen = a.rep.length(); long i; _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); const _ntl_ulong *bp = b.rep.elts(); for (i = 0; i < wlen; i++) xp[i] = ap[i] ^ bp[i]; } void clear(vec_GF2& x) { long wlen = x.rep.length(); long i; _ntl_ulong *xp = x.rep.elts(); for (i = 0; i < wlen; i++) xp[i] = 0; } long IsZero(const vec_GF2& x) { long wlen = x.rep.length(); long i; const _ntl_ulong *xp = x.rep.elts(); for (i = 0; i < wlen; i++) if (xp[i] != 0) return 0; return 1; } vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b) { vec_GF2 res; add(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b) { vec_GF2 res; add(res, a, b); NTL_OPT_RETURN(vec_GF2, res); } static void ShiftToHigh(vec_GF2& x, const vec_GF2& a, long n) // assumes 0 <= n < a.length() { long l = a.length(); x.SetLength(l); _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sa = a.rep.length(); long i; if (bn == 0) { for (i = sa-1; i >= wn; i--) xp[i] = ap[i-wn]; for (i = wn-1; i >= 0; i--) xp[i] = 0; } else { for (i = sa-1; i >= wn+1; i--) xp[i] = (ap[i-wn] << bn) | (ap[i-wn-1] >> (NTL_BITS_PER_LONG-bn)); xp[wn] = ap[0] << bn; for (i = wn-1; i >= 0; i--) xp[i] = 0; } long p = l % NTL_BITS_PER_LONG; if (p != 0) xp[sa-1] &= (1UL << p) - 1UL; } static void ShiftToLow(vec_GF2& x, const vec_GF2& a, long n) // assumes 0 <= n < a.length() { long l = a.length(); x.SetLength(l); _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; long sa = a.rep.length(); long i; if (bn == 0) { for (i = 0; i < sa-wn; i++) xp[i] = ap[i+wn]; } else { for (i = 0; i < sa-wn-1; i++) xp[i] = (ap[i+wn] >> bn) | (ap[i+wn+1] << (NTL_BITS_PER_LONG - bn)); xp[sa-wn-1] = ap[sa-1] >> bn; } for (i = sa-wn; i < sa; i++) xp[i] = 0; } void shift(vec_GF2& x, const vec_GF2& a, long n) { long l = a.length(); if (n >= l || n <= -l) { x.SetLength(l); clear(x); } else if (n < 0) ShiftToLow(x, a, -n); // |n| < l, so -n won't overflow! else ShiftToHigh(x, a, n); } // This code is simply canibalized from GF2X.c... // so much for "code re-use" and "modularity" static const _ntl_ulong revtab[256] = { 0UL, 128UL, 64UL, 192UL, 32UL, 160UL, 96UL, 224UL, 16UL, 144UL, 80UL, 208UL, 48UL, 176UL, 112UL, 240UL, 8UL, 136UL, 72UL, 200UL, 40UL, 168UL, 104UL, 232UL, 24UL, 152UL, 88UL, 216UL, 56UL, 184UL, 120UL, 248UL, 4UL, 132UL, 68UL, 196UL, 36UL, 164UL, 100UL, 228UL, 20UL, 148UL, 84UL, 212UL, 52UL, 180UL, 116UL, 244UL, 12UL, 140UL, 76UL, 204UL, 44UL, 172UL, 108UL, 236UL, 28UL, 156UL, 92UL, 220UL, 60UL, 188UL, 124UL, 252UL, 2UL, 130UL, 66UL, 194UL, 34UL, 162UL, 98UL, 226UL, 18UL, 146UL, 82UL, 210UL, 50UL, 178UL, 114UL, 242UL, 10UL, 138UL, 74UL, 202UL, 42UL, 170UL, 106UL, 234UL, 26UL, 154UL, 90UL, 218UL, 58UL, 186UL, 122UL, 250UL, 6UL, 134UL, 70UL, 198UL, 38UL, 166UL, 102UL, 230UL, 22UL, 150UL, 86UL, 214UL, 54UL, 182UL, 118UL, 246UL, 14UL, 142UL, 78UL, 206UL, 46UL, 174UL, 110UL, 238UL, 30UL, 158UL, 94UL, 222UL, 62UL, 190UL, 126UL, 254UL, 1UL, 129UL, 65UL, 193UL, 33UL, 161UL, 97UL, 225UL, 17UL, 145UL, 81UL, 209UL, 49UL, 177UL, 113UL, 241UL, 9UL, 137UL, 73UL, 201UL, 41UL, 169UL, 105UL, 233UL, 25UL, 153UL, 89UL, 217UL, 57UL, 185UL, 121UL, 249UL, 5UL, 133UL, 69UL, 197UL, 37UL, 165UL, 101UL, 229UL, 21UL, 149UL, 85UL, 213UL, 53UL, 181UL, 117UL, 245UL, 13UL, 141UL, 77UL, 205UL, 45UL, 173UL, 109UL, 237UL, 29UL, 157UL, 93UL, 221UL, 61UL, 189UL, 125UL, 253UL, 3UL, 131UL, 67UL, 195UL, 35UL, 163UL, 99UL, 227UL, 19UL, 147UL, 83UL, 211UL, 51UL, 179UL, 115UL, 243UL, 11UL, 139UL, 75UL, 203UL, 43UL, 171UL, 107UL, 235UL, 27UL, 155UL, 91UL, 219UL, 59UL, 187UL, 123UL, 251UL, 7UL, 135UL, 71UL, 199UL, 39UL, 167UL, 103UL, 231UL, 23UL, 151UL, 87UL, 215UL, 55UL, 183UL, 119UL, 247UL, 15UL, 143UL, 79UL, 207UL, 47UL, 175UL, 111UL, 239UL, 31UL, 159UL, 95UL, 223UL, 63UL, 191UL, 127UL, 255UL }; static inline _ntl_ulong rev1(_ntl_ulong a) { return NTL_BB_REV_CODE; } void reverse(vec_GF2& c, const vec_GF2& a) // c = reverse of a { long n = a.length(); c = a; if (n <= 0) { return; } long wn = n/NTL_BITS_PER_LONG; long bn = n - wn*NTL_BITS_PER_LONG; if (bn != 0) { wn++; bn = NTL_BITS_PER_LONG - bn; } _ntl_ulong *cp = c.rep.elts(); long i; if (bn != 0) { for (i = wn-1; i >= 1; i--) cp[i] = (cp[i] << bn) | (cp[i-1] >> (NTL_BITS_PER_LONG-bn)); cp[0] = cp[0] << bn; } for (i = 0; i < wn/2; i++) { _ntl_ulong t; t = cp[i]; cp[i] = cp[wn-1-i]; cp[wn-1-i] = t; } for (i = 0; i < wn; i++) cp[i] = rev1(cp[i]); } static long weight1(_ntl_ulong a) { long res = 0; while (a) { if (a & 1) res ++; a >>= 1; } return res; } long weight(const vec_GF2& a) { long wlen = a.rep.length(); long res = 0; long i; for (i = 0; i < wlen; i++) res += weight1(a.rep[i]); return res; } void random(vec_GF2& x, long n) { if (n < 0) LogicError("random: bad arg"); x.SetLength(n); long wl = x.rep.length(); VectorRandomWord(wl-1, x.rep.elts()); if (n > 0) { long pos = n % NTL_BITS_PER_LONG; if (pos == 0) pos = NTL_BITS_PER_LONG; x.rep[wl-1] = RandomBits_ulong(pos); } } void VectorCopy(vec_GF2& x, const vec_GF2& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long wn = (n + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; long wm = (m + NTL_BITS_PER_LONG - 1)/NTL_BITS_PER_LONG; _ntl_ulong *xp = x.rep.elts(); const _ntl_ulong *ap = a.rep.elts(); long i; for (i = 0; i < wm; i++) xp[i] = ap[i]; for (i = wm; i < wn; i++) xp[i] = 0; long p = n % NTL_BITS_PER_LONG; if (p != 0) { xp[wn-1] &= ((1UL << p) - 1UL); } } NTL_END_IMPL ntl-11.5.1/src/vec_GF2E.cpp0000644417616742025610000000760114064716022016774 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL static void BasicBlockConstruct(GF2E* x, long n, long d) { long m, j; long i = 0; NTL_SCOPE(guard) { BlockDestroy(x, i); }; while (i < n) { m = WV_BlockConstructAlloc(x[i]._GF2E__rep.xrep, d, n-i); for (j = 1; j < m; j++) WV_BlockConstructSet(x[i]._GF2E__rep.xrep, x[i+j]._GF2E__rep.xrep, j); i += m; } guard.relax(); } void BlockConstruct(GF2E* x, long n) { if (n <= 0) return; if (!GF2EInfo) LogicError("GF2E constructor called while modulus undefined"); long d = GF2E::WordLength(); BasicBlockConstruct(x, n, d); } void BlockConstructFromVec(GF2E* x, long n, const GF2E* y) { if (n <= 0) return; long d = y->_GF2E__rep.xrep.MaxLength(); BasicBlockConstruct(x, n, d); NTL_SCOPE(guard) { BlockDestroy(x, n); }; long i; for (i = 0; i < n; i++) x[i] = y[i]; guard.relax(); } void BlockConstructFromObj(GF2E* x, long n, const GF2E& y) { if (n <= 0) return; if (!GF2EInfo) LogicError("GF2E constructor called while modulus undefined"); long d = GF2E::WordLength(); BasicBlockConstruct(x, n, d); NTL_SCOPE(guard) { BlockDestroy(x, n); }; long i; for (i = 0; i < n; i++) x[i] = y; guard.relax(); } void BlockDestroy(GF2E* x, long n) { if (n <= 0) return; long i = 0; long m; while (i < n) { m = WV_BlockDestroy(x[i]._GF2E__rep.xrep); i += m; } } void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { long n = min(a.length(), b.length()); long i; GF2X accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; GF2X accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b_in) { GF2E b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b) { x = a; if (b == 0) clear(x); } void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void clear(vec_GF2E& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_GF2E& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b) { vec_GF2E res; add(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b) { vec_GF2E res; sub(res, a, b); NTL_OPT_RETURN(vec_GF2E, res); } vec_GF2E operator-(const vec_GF2E& a) { vec_GF2E res; negate(res, a); NTL_OPT_RETURN(vec_GF2E, res); } GF2E operator*(const vec_GF2E& a, const vec_GF2E& b) { GF2E res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } void random(vec_GF2E& x, long n) { x.SetLength(n); for (long i = 0; i < n; i++) random(x[i]); } NTL_END_IMPL ntl-11.5.1/src/vec_RR.cpp0000644417616742025610000000451214064716022016632 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void InnerProduct(RR& xx, const vec_RR& a, const vec_RR& b) { RR t1, x; long n = min(a.length(), b.length()); long i; clear(x); for (i = 1; i <= n; i++) { mul(t1, a(i), b(i)); add(x, x, t1); } xx = x; } void mul(vec_RR& x, const vec_RR& a, const RR& b_in) { RR b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_RR& x, const vec_RR& a, double b_in) { NTL_TLS_LOCAL(RR, b); conv(b, b_in); long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_RR& x, const vec_RR& a, const vec_RR& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_RR& x, const vec_RR& a, const vec_RR& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_RR& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_RR& x, const vec_RR& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_RR& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_RR operator+(const vec_RR& a, const vec_RR& b) { vec_RR res; add(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator-(const vec_RR& a, const vec_RR& b) { vec_RR res; sub(res, a, b); NTL_OPT_RETURN(vec_RR, res); } vec_RR operator-(const vec_RR& a) { vec_RR res; negate(res, a); NTL_OPT_RETURN(vec_RR, res); } RR operator*(const vec_RR& a, const vec_RR& b) { RR res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_RR& x, const vec_RR& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-11.5.1/src/vec_ZZ.cpp0000644417616742025610000000445214064716022016655 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void InnerProduct(ZZ& xx, const vec_ZZ& a, const vec_ZZ& b) { ZZ t1, x; long n = min(a.length(), b.length()); long i; clear(x); for (i = 1; i <= n; i++) { mul(t1, a(i), b(i)); add(x, x, t1); } xx = x; } void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b_in) { ZZ b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ& x, const vec_ZZ& a, long b) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_ZZ& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_ZZ& x, const vec_ZZ& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_ZZ& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b) { vec_ZZ res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b) { vec_ZZ res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ, res); } vec_ZZ operator-(const vec_ZZ& a) { vec_ZZ res; negate(res, a); NTL_OPT_RETURN(vec_ZZ, res); } ZZ operator*(const vec_ZZ& a, const vec_ZZ& b) { ZZ res; InnerProduct(res, a, b); NTL_OPT_RETURN(ZZ, res); } void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } NTL_END_IMPL ntl-11.5.1/src/vec_ZZ_p.cpp0000644417616742025610000001224014064716022017166 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL #define PAR_THRESH (4000.0) static inline bool BelowThresh(long n) { return double(n)*double(ZZ_p::ModulusSize()) < PAR_THRESH; } static void BasicBlockConstruct(ZZ_p* x, long n, long d) { long m, j; long i = 0; NTL_SCOPE(guard) { BlockDestroy(x, i); }; while (i < n) { m = ZZ_BlockConstructAlloc(x[i]._ZZ_p__rep, d, n-i); for (j = 1; j < m; j++) ZZ_BlockConstructSet(x[i]._ZZ_p__rep, x[i+j]._ZZ_p__rep, j); i += m; } guard.relax(); } void BlockConstruct(ZZ_p* x, long n) { if (n <= 0) return; if (!ZZ_pInfo) LogicError("ZZ_p constructor called while modulus undefined"); long d = ZZ_p::ModulusSize(); BasicBlockConstruct(x, n, d); } void BlockConstructFromVec(ZZ_p* x, long n, const ZZ_p* y) { if (n <= 0) return; long d = y->_ZZ_p__rep.MaxAlloc() - 1; BasicBlockConstruct(x, n, d); NTL_SCOPE(guard) { BlockDestroy(x, n); }; long i; for (i = 0; i < n; i++) x[i] = y[i]; guard.relax(); } void BlockConstructFromObj(ZZ_p* x, long n, const ZZ_p& y) { if (n <= 0) return; if (!ZZ_pInfo) LogicError("ZZ_p constructor called while modulus undefined"); long d = ZZ_p::ModulusSize(); BasicBlockConstruct(x, n, d); NTL_SCOPE(guard) { BlockDestroy(x, n); }; long i; for (i = 0; i < n; i++) x[i] = y; guard.relax(); } void BlockDestroy(ZZ_p* x, long n) { if (n <= 0) return; long i = 0; long m; while (i < n) { m = ZZ_BlockDestroy(x[i]._ZZ_p__rep); i += m; } } void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = min(a.length(), b.length()); long i; NTL_ZZRegister(accum); NTL_ZZRegister(t); clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; NTL_ZZRegister(accum); NTL_ZZRegister(t); clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void clear(vec_ZZ_p& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } void negate(vec_ZZ_p& x, const vec_ZZ_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } long IsZero(const vec_ZZ_p& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ_p, res); } vec_ZZ_p operator-(const vec_ZZ_p& a) { vec_ZZ_p res; negate(res, a); NTL_OPT_RETURN(vec_ZZ_p, res); } ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b) { ZZ_p res; InnerProduct(res, a, b); NTL_OPT_RETURN(ZZ_p, res); } void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } void random(vec_ZZ_p& x, long n) { x.SetLength(n); for (long i = 0; i < n; i++) random(x[i]); } // thread-boosted conversion. // This is used in the implementation of ZZ_pX multiplication in terms // of ZZX SSMul. void conv(vec_ZZ_p& x, const vec_ZZ& a) { long n = a.length(); x.SetLength(n); if (n == 0) return; const ZZ *ap = a.elts(); ZZ_p *xp = x.elts(); ZZ_pContext context; context.save(); bool seq = BelowThresh(n); NTL_GEXEC_RANGE(seq, n, first, last) NTL_IMPORT(ap) NTL_IMPORT(xp) context.restore(); for (long i = first; i < last; i++) conv(xp[i], ap[i]); NTL_GEXEC_RANGE_END } NTL_END_IMPL ntl-11.5.1/src/vec_ZZ_pE.cpp0000644417616742025610000000637014064716022017302 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = min(a.length(), b.length()); long i; ZZ_pX accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; ZZ_pX accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b_in) { ZZ_pE b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b_in) { NTL_ZZ_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } void clear(vec_ZZ_pE& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_ZZ_pE& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; add(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE res; sub(res, a, b); NTL_OPT_RETURN(vec_ZZ_pE, res); } vec_ZZ_pE operator-(const vec_ZZ_pE& a) { vec_ZZ_pE res; negate(res, a); NTL_OPT_RETURN(vec_ZZ_pE, res); } ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { ZZ_pE res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } void random(vec_ZZ_pE& x, long n) { x.SetLength(n); for (long i = 0; i < n; i++) random(x[i]); } NTL_END_IMPL ntl-11.5.1/src/vec_lzz_p.cpp0000644417616742025610000001260014064716022017442 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL // NOTE: the signature for this is in lzz_p.h void conv(vec_zz_p& x, const vec_ZZ& a) { long i, n; n = a.length(); x.SetLength(n); VectorConv(n, x.elts(), a.elts()); } // NOTE: the signature for this is in lzz_p.h void conv(vec_zz_p& x, const Vec& a) { long i, n; n = a.length(); x.SetLength(n); VectorConv(n, x.elts(), a.elts()); } void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = min(a.length(), b.length()); long i; long accum, t; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); const zz_p *ap = a.elts(); const zz_p *bp = b.elts(); accum = 0; for (i = 0; i < n; i++) { t = MulMod(rep(ap[i]), rep(bp[i]), p, pinv); accum = AddMod(accum, t, p); } x.LoopHole() = accum; } void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; long accum, t; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); const zz_p *ap = a.elts(); const zz_p *bp = b.elts(); accum = 0; for (i = offset; i < n; i++) { t = MulMod(rep(ap[i]), rep(bp[i-offset]), p, pinv); accum = AddMod(accum, t, p); } x.LoopHole() = accum; } long CRT(vec_ZZ& gg, ZZ& a, const vec_zz_p& G) { long n = gg.length(); if (G.length() != n) LogicError("CRT: vector length mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg[i], a)) { modified = 1; rem(g, gg[i], a); if (g > a1) sub(g, g, a); } else g = gg[i]; h = rem(g, p); h = SubMod(rep(G[i]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i] = g; } a = new_a; return modified; } void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b) { long n = a.length(); x.SetLength(n); long i; if (n <= 1) { for (i = 0; i < n; i++) mul(x[i], a[i], b); } else { long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long bb = rep(b); mulmod_precon_t bpinv = PrepMulModPrecon(bb, p, pinv); const zz_p *ap = a.elts(); zz_p *xp = x.elts(); for (i = 0; i < n; i++) xp[i].LoopHole() = MulModPrecon(rep(ap[i]), bb, p, bpinv); } } void mul(vec_zz_p& x, const vec_zz_p& a, long b_in) { zz_p b; b = b_in; mul(x, a, b); } void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); long p = zz_p::modulus(); x.SetLength(n); const zz_p *ap = a.elts(); const zz_p *bp = b.elts(); zz_p *xp = x.elts(); long i; for (i = 0; i < n; i++) xp[i].LoopHole() = AddMod(rep(ap[i]), rep(bp[i]), p); } void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); long p = zz_p::modulus(); x.SetLength(n); const zz_p *ap = a.elts(); const zz_p *bp = b.elts(); zz_p *xp = x.elts(); long i; for (i = 0; i < n; i++) xp[i].LoopHole() = SubMod(rep(ap[i]), rep(bp[i]), p); } void clear(vec_zz_p& x) { long n = x.length(); zz_p *xp = x.elts(); long i; for (i = 0; i < n; i++) clear(xp[i]); } void negate(vec_zz_p& x, const vec_zz_p& a) { long n = a.length(); long p = zz_p::modulus(); x.SetLength(n); const zz_p *ap = a.elts(); zz_p *xp = x.elts(); long i; for (i = 0; i < n; i++) xp[i].LoopHole() = NegateMod(rep(ap[i]), p); } long IsZero(const vec_zz_p& a) { long n = a.length(); const zz_p *ap = a.elts(); long i; for (i = 0; i < n; i++) if (!IsZero(ap[i])) return 0; return 1; } vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b) { vec_zz_p res; add(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b) { vec_zz_p res; sub(res, a, b); NTL_OPT_RETURN(vec_zz_p, res); } vec_zz_p operator-(const vec_zz_p& a) { vec_zz_p res; negate(res, a); NTL_OPT_RETURN(vec_zz_p, res); } zz_p operator*(const vec_zz_p& a, const vec_zz_p& b) { zz_p res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); const zz_p *ap = a.elts(); zz_p *xp = x.elts(); long i; for (i = 0; i < m; i++) xp[i] = ap[i]; for (i = m; i < n; i++) clear(xp[i]); } void random(vec_zz_p& x, long n) { x.SetLength(n); VectorRandom(n, x.elts()); } NTL_END_IMPL ntl-11.5.1/src/vec_lzz_pE.cpp0000644417616742025610000000637014064716022017556 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = min(a.length(), b.length()); long i; zz_pX accum, t; clear(accum); for (i = 0; i < n; i++) { mul(t, rep(a[i]), rep(b[i])); add(accum, accum, t); } conv(x, accum); } void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; zz_pX accum, t; clear(accum); for (i = offset; i < n; i++) { mul(t, rep(a[i]), rep(b[i-offset])); add(accum, accum, t); } conv(x, accum); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b_in) { zz_pE b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b_in) { NTL_zz_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void mul(vec_zz_pE& x, const vec_zz_pE& a, long b_in) { NTL_zz_pRegister(b); b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); } void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = a.length(); if (b.length() != n) LogicError("vector add: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) add(x[i], a[i], b[i]); } void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); } void negate(vec_zz_pE& x, const vec_zz_pE& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); } void clear(vec_zz_pE& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); } long IsZero(const vec_zz_pE& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; } vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; add(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b) { vec_zz_pE res; sub(res, a, b); NTL_OPT_RETURN(vec_zz_pE, res); } vec_zz_pE operator-(const vec_zz_pE& a) { vec_zz_pE res; negate(res, a); NTL_OPT_RETURN(vec_zz_pE, res); } zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b) { zz_pE res; InnerProduct(res, a, b); return res; } void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); } void random(vec_zz_pE& x, long n) { x.SetLength(n); for (long i = 0; i < n; i++) random(x[i]); } NTL_END_IMPL ntl-11.5.1/src/xdouble.cpp0000644417616742025610000003426014064716022017117 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL NTL_CHEAP_THREAD_LOCAL long xdouble::oprec = 10; void xdouble::SetOutputPrecision(long p) { if (p < 1) p = 1; if (NTL_OVERFLOW(p, 1, 0)) ResourceError("xdouble: output precision too big"); oprec = p; } void xdouble::normalize() { if (x == 0) e = 0; else if (x > 0) { while (x < NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; } while (x > NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; } } else { while (x > -NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; } while (x < -NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; } } if (e >= NTL_OVFBND) ResourceError("xdouble: overflow"); if (e <= -NTL_OVFBND) ResourceError("xdouble: underflow"); } xdouble to_xdouble(double a) { if (a == 0 || a == 1 || (a > 0 && a >= NTL_XD_HBOUND_INV && a <= NTL_XD_HBOUND) || (a < 0 && a <= -NTL_XD_HBOUND_INV && a >= -NTL_XD_HBOUND)) { return xdouble(a, 0); } if (!IsFinite(&a)) ArithmeticError("double to xdouble conversion: non finite value"); xdouble z = xdouble(a, 0); z.normalize(); return z; } void conv(double& xx, const xdouble& a) // This is implemented so that if a can be represented exactly // as a double, then it will be. If not, it will be represented // as best as possible: as infinity if the exponent is too large, // or as zero (or possibly denormalized number) if the exponent // is too small. Even for very large or small exponents, it // is designed to be fairly efficient. { double x; long e; x = a.x; e = a.e; if (x == 0 || e == 0) { xx = x; return; } long e_neg = 0; if (e < 0) { e = -e; e_neg = 1; } double base = e_neg ? NTL_XD_BOUND_INV : NTL_XD_BOUND; // set x = x * base^e if (e < 4) { while (e > 0) { x *= base; e--; } } else { // repeated squaring from low to high, but with high bit // treated seperately to avoid unnecessary exponent // overflow/underflow // this code requires e >= 2 if (e % 2) x *= base; e /= 2; while (e > 1) { base *= base; if (e % 2) x *= base; e /= 2; } // last step: multiply by base^2, one multply at a time. // Doing it this way prevents unnecessary exponent overflow/ // underflow. x *= base; x *= base; } xx = x; } xdouble operator+(const xdouble& a, const xdouble& b) { xdouble z; if (a.x == 0) return b; if (b.x == 0) return a; if (a.e == b.e) { z.x = a.x + b.x; z.e = a.e; z.normalize(); return z; } else if (a.e > b.e) { if (a.e > b.e+1) return a; z.x = a.x + b.x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return z; } else { if (b.e > a.e+1) return b; z.x = a.x*NTL_XD_BOUND_INV + b.x; z.e = b.e; z.normalize(); return z; } } xdouble operator-(const xdouble& a, const xdouble& b) { xdouble z; if (a.x == 0) return -b; if (b.x == 0) return a; if (a.e == b.e) { z.x = a.x - b.x; z.e = a.e; z.normalize(); return z; } else if (a.e > b.e) { if (a.e > b.e+1) return a; z.x = a.x - b.x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return z; } else { if (b.e > a.e+1) return -b; z.x = a.x*NTL_XD_BOUND_INV - b.x; z.e = b.e; z.normalize(); return z; } } xdouble operator-(const xdouble& a) { xdouble z; z.x = -a.x; z.e = a.e; return z; } xdouble operator*(const xdouble& a, const xdouble& b) { xdouble z; z.e = a.e + b.e; z.x = a.x * b.x; z.normalize(); return z; } xdouble operator/(const xdouble& a, const xdouble& b) { xdouble z; if (b.x == 0) ArithmeticError("xdouble division by 0"); z.e = a.e - b.e; z.x = a.x / b.x; z.normalize(); return z; } long compare(const xdouble& a, const xdouble& b) { xdouble z = a - b; if (z.x < 0) return -1; else if (z.x == 0) return 0; else return 1; } long sign(const xdouble& z) { if (z.x < 0) return -1; else if (z.x == 0) return 0; else return 1; } xdouble trunc(const xdouble& a) { if (a.x >= 0) return floor(a); else return ceil(a); } xdouble floor(const xdouble& aa) { xdouble z; xdouble a = aa; ForceToMem(&a.x); if (a.e == 0) { z.x = floor(a.x); z.e = 0; z.normalize(); return z; } else if (a.e > 0) { return a; } else { if (a.x < 0) return to_xdouble(-1); else return to_xdouble(0); } } xdouble ceil(const xdouble& aa) { xdouble z; xdouble a = aa; ForceToMem(&a.x); if (a.e == 0) { z.x = ceil(a.x); z.e = 0; z.normalize(); return z; } else if (a.e > 0) { return a; } else { if (a.x < 0) return to_xdouble(0); else return to_xdouble(1); } } xdouble to_xdouble(const ZZ& a) { RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); NTL_TLS_LOCAL(RR, t); conv(t, a); double x; conv(x, t.mantissa()); xdouble y, z, res; conv(y, x); power2(z, t.exponent()); res = y*z; return res; } void conv(ZZ& x, const xdouble& a) { xdouble b = floor(a); RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); NTL_TLS_LOCAL(RR, t); conv(t, b); conv(x, t); } xdouble fabs(const xdouble& a) { xdouble z; z.e = a.e; z.x = fabs(a.x); return z; } xdouble sqrt(const xdouble& a) { if (a == 0) return to_xdouble(0); if (a < 0) ArithmeticError("xdouble: sqrt of negative number"); xdouble t; if (a.e & 1) { t.e = (a.e - 1)/2; t.x = sqrt(a.x * NTL_XD_BOUND); } else { t.e = a.e/2; t.x = sqrt(a.x); } t.normalize(); return t; } void power(xdouble& z, const xdouble& a, const ZZ& e) { xdouble b, res; b = a; res = 1; long n = NumBits(e); long i; for (i = n-1; i >= 0; i--) { res = res * res; if (bit(e, i)) res = res * b; } if (sign(e) < 0) z = 1/res; else z = res; } void power(xdouble& z, const xdouble& a, long e) { NTL_ZZRegister(E); E = e; power(z, a, E); } void power2(xdouble& z, long e) { long hb = NTL_XD_HBOUND_LOG; long b = 2*hb; long q, r; q = e/b; r = e%b; while (r >= hb) { r -= b; q++; } while (r < -hb) { r += b; q--; } if (q >= NTL_OVFBND) ResourceError("xdouble: overflow"); if (q <= -NTL_OVFBND) ResourceError("xdouble: underflow"); double x = _ntl_ldexp(1.0, r); z.x = x; z.e = q; } void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c) // z = a + b*c { double x; long e; e = b.e + c.e; x = b.x * c.x; if (x == 0) { z = a; return; } if (a.x == 0) { z.e = e; z.x = x; z.normalize(); return; } if (a.e == e) { z.x = a.x + x; z.e = e; z.normalize(); return; } else if (a.e > e) { if (a.e > e+1) { z = a; return; } z.x = a.x + x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return; } else { if (e > a.e+1) { z.x = x; z.e = e; z.normalize(); return; } z.x = a.x*NTL_XD_BOUND_INV + x; z.e = e; z.normalize(); return; } } void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c) // z = a - b*c { double x; long e; e = b.e + c.e; x = b.x * c.x; if (x == 0) { z = a; return; } if (a.x == 0) { z.e = e; z.x = -x; z.normalize(); return; } if (a.e == e) { z.x = a.x - x; z.e = e; z.normalize(); return; } else if (a.e > e) { if (a.e > e+1) { z = a; return; } z.x = a.x - x*NTL_XD_BOUND_INV; z.e = a.e; z.normalize(); return; } else { if (e > a.e+1) { z.x = -x; z.e = e; z.normalize(); return; } z.x = a.x*NTL_XD_BOUND_INV - x; z.e = e; z.normalize(); return; } } double log(const xdouble& a) { static const double LogBound = log(NTL_XD_BOUND); // GLOBAL (assumes C++11 thread-safe init) if (a.x <= 0) { ArithmeticError("log(xdouble): argument must be positive"); } return log(a.x) + a.e*LogBound; } xdouble xexp(double x) { const double LogBound = log(NTL_XD_BOUND); double y = x/LogBound; double iy = floor(y+0.5); if (iy >= NTL_OVFBND) ResourceError("xdouble: overflow"); if (iy <= -NTL_OVFBND) ResourceError("xdouble: underflow"); double fy = y - iy; xdouble res; res.e = long(iy); res.x = exp(fy*LogBound); res.normalize(); return res; } /************** input / output routines **************/ void ComputeLn2(RR&); void ComputeLn10(RR&); long ComputeMax10Power() { RRPush push; RR::SetPrecision(NTL_BITS_PER_LONG); RR ln2, ln10; ComputeLn2(ln2); ComputeLn10(ln10); long k = to_long( to_RR(NTL_OVFBND/2) * ln2 / ln10 ); return k; } xdouble PowerOf10(const ZZ& e) { static NTL_CHEAP_THREAD_LOCAL long init = 0; static NTL_CHEAP_THREAD_LOCAL long k = 0; NTL_TLS_LOCAL(xdouble, v10k); if (!init) { k = ComputeMax10Power(); RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); v10k = to_xdouble(power(to_RR(10), k)); init = 1; } ZZ e1; long neg; if (e < 0) { e1 = -e; neg = 1; } else { e1 = e; neg = 0; } long r; ZZ q; r = DivRem(q, e1, k); RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); xdouble x1 = to_xdouble(power(to_RR(10), r)); xdouble x2 = power(v10k, q); xdouble x3 = x1*x2; if (neg) x3 = 1/x3; return x3; } ostream& operator<<(ostream& s, const xdouble& a) { if (a == 0) { s << "0"; return s; } RRPush push; long temp_p = long(log(fabs(log(fabs(a))) + 1.0)/log(2.0)) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; ZZ log_10_a = to_ZZ( (to_RR(a.e)*to_RR(2*NTL_XD_HBOUND_LOG) + log(fabs(a.x))/log(2.0))/log_2_10); xdouble b; long neg; if (a < 0) { b = -a; neg = 1; } else { b = a; neg = 0; } ZZ k = xdouble::OutputPrecision() - log_10_a; xdouble c, d; c = PowerOf10(to_ZZ(xdouble::OutputPrecision())); d = PowerOf10(log_10_a); b = b / d; b = b * c; while (b < c) { b = b * 10.0; k++; } while (b >= c) { b = b / 10.0; k--; } b = b + 0.5; k = -k; ZZ B; conv(B, b); long bp_len = xdouble::OutputPrecision()+10; UniqueArray bp_store; bp_store.SetLength(bp_len); char *bp = bp_store.get(); long len, i; len = 0; do { if (len >= bp_len) LogicError("xdouble output: buffer overflow"); bp[len] = IntValToChar(DivRem(B, B, 10)); len++; } while (B > 0); for (i = 0; i < len/2; i++) { char tmp; tmp = bp[i]; bp[i] = bp[len-1-i]; bp[len-1-i] = tmp; } i = len-1; while (bp[i] == '0') i--; k += (len-1-i); len = i+1; bp[len] = '\0'; if (k > 3 || k < -len - 3) { // use scientific notation if (neg) s << "-"; s << "0." << bp << "e" << (k + len); } else { long kk = to_long(k); if (kk >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < kk; i++) s << "0"; } else if (kk <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-kk; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+kk; i++) s << bp[i]; s << "."; for (i = len+kk; i < len; i++) s << bp[i]; } } return s; } istream& operator>>(istream& s, xdouble& x) { long c; long cval; long sign; ZZ a, b; if (!s) NTL_INPUT_ERROR(s, "bad xdouble input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c == '-') { sign = -1; s.get(); c = s.peek(); } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; s.get(); c = s.peek(); cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); s.get(); c = s.peek(); cval = CharToIntVal(c); } } } if (got_dot && !got1 && !got2) NTL_INPUT_ERROR(s, "bad xdouble input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; s.get(); c = s.peek(); if (c == '-') { e_sign = -1; s.get(); c = s.peek(); } else if (c == '+') { e_sign = 1; s.get(); c = s.peek(); } else e_sign = 1; cval = CharToIntVal(c); if (cval < 0 || cval > 9) NTL_INPUT_ERROR(s, "bad xdouble input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); s.get(); c = s.peek(); cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) NTL_INPUT_ERROR(s, "bad xdouble input"); xdouble t1, t2, v; if (got1 || got2) { conv(t1, a); conv(t2, b); v = t1/t2; } else v = 1; if (sign < 0) v = -v; if (got_e) { if (e_sign < 0) negate(e, e); t1 = PowerOf10(e); v = v * t1; } x = v; return s; } NTL_END_IMPL ntl-11.5.1/src/G_LLL_FP.cpp0000644417616742025610000007660014064716022016737 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) ResourceError("G_LLL_FP: numbers too big...use G_LLL_XD"); } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(double *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i]); if (t > res) res = t; } return res; } static void RowTransformStart(double *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i] < TR_BND && a[i] > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, double *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, double *a, double *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; conv(mu, MU1); CheckFinite(&mu); long n = A.length(); long i; if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i] -= b[i]; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i] += b[i]; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i] -= mu*b[i]; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] -= b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < TR_BND && b[i] > -TR_BND) { a[i] += b[i]; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i] < TR_BND && a[i] > -TR_BND && b[i] < b_bnd && b[i] > -b_bnd) { a[i] -= b[i]*mu; } else { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i]); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_FP { public: GivensCache_FP(long m, long n); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; Unique2DArray buf; UniqueArray bl; UniqueArray bv; long bp; }; GivensCache_FP::GivensCache_FP(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; buf.SetDims(sz, n+1); bl.SetLength(sz); bv.SetLength(sz); long i; for (i = 0; i < sz; i++) bl[i] = 0; for (i = 0; i < sz; i++) bv[i] = 0; bp = 0; } void GivensCache_FP::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_FP::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_FP::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_FP::swap() { swap(bl[bp] - 1); } void GivensCache_FP::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_FP::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(double **B1, double **mu, double **aux, long k, long n, GivensCache_FP& cache) { long i, j; double c, s, a, b, t; double *p = mu[k]; double *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { double *cptr = mu[i]; double *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { double *cptr = mu[i]; double *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) LogicError("G_LLL_FP: internal error"); if (k > n) p[k] = 0; for (i = 1; i <= k; i++) CheckFinite(&p[i]); } static NTL_CHEAP_THREAD_LOCAL double red_fudge = 0; static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_FP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("G_LLL_FP: too much loss of precision...stop!"); } #if 0 static void print_mus(double **mu, long k) { long i; for (i = k-1; i >= 1; i--) cerr << mu[k][i] << " "; cerr << "\n"; } #endif static long ll_G_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check, double **B1, double **mu, double **aux, long m, long init_k, long &quit, GivensCache_FP& cache) { long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; double mu1; double t1; ZZ T1; double *tp; double half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); UniqueArray max_b_store; max_b_store.SetLength(m+1); double *max_b = max_b_store.get(); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; long swap_cnt = 0; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; swap_cnt = 0; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); if (swap_cnt > 200000) { cerr << "G_LLL_FP: swap loop?\n"; swap_cnt = 0; } counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; long sz=0, new_sz; do { // size reduction counter++; if ((counter & 127) == 0) { new_sz = 0; for (j = 1; j <= n; j++) new_sz += NumBits(B(k,j)); if ((counter >> 7) == 1 || new_sz < sz) { sz = new_sz; } else { cerr << "G_LLL_FP: warning--infinite loop? (" << k << ")\n"; } } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-0.5); else mu1 = floor(mu1+0.5); double *mu_k = mu[k]; double *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; t1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = t1; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions LogicError("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k > 1 && sqrt(delta - mu[k][k-1]*mu[k][k-1])*fabs(mu[k-1][k-1]) > fabs(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; t1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = t1; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; swap_cnt++; // cout << "-\n"; } else { cache.incr(); k++; // cout << "+\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_FP(mat_ZZ& B, mat_ZZ* U, double delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; ZZ MU; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); double **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, n+2); double **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+1, n+1); double **aux = aux_store.get(); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_FP cache(m, n); new_m = ll_G_LLL_FP(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long G_LLL_FP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_FP: bad delta"); if (deep < 0) LogicError("G_LLL_FP: bad deep"); return G_LLL_FP(B, 0, delta, deep, check); } long G_LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_FP: bad delta"); if (deep < 0) LogicError("G_LLL_FP: bad deep"); return G_LLL_FP(B, &U, delta, deep, check); } NTL_TLS_GLOBAL_DECL(vec_double, G_BKZConstant) static void ComputeG_BKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; G_BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_double, G_BKZThresh) static void ComputeG_BKZThresh(double *c, long beta) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); G_BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = exp(x/double(i))*G_BKZConstant(i); if (!IsFinite(&G_BKZThresh(i))) G_BKZThresh(i) = 0; } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_FP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_FP(mat_ZZ& BB, mat_ZZ* UU, double delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; double t1; ZZ T1; double *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); double **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, n+2); double **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+2, n+1); double **aux = aux_store.get(); UniqueArray c_store; c_store.SetLength(m+2); double *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors double cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); double *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); double *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); double *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); double *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); double *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get(); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_FP cache(m, n); m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) t1 += utildavec[i]*mu[i][t]; yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta - 8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("G_BKZ_FP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) LogicError("G_BKZ_FP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) LogicError("G_BKZ_FP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_FP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) LogicError("G_BKZ_FP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_FP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_FP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_FP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_FP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_FP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_FP: bad delta"); if (beta < 2) LogicError("G_BKZ_FP: bad block size"); return G_BKZ_FP(BB, &UU, delta, beta, prune, check); } long G_BKZ_FP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_FP: bad delta"); if (beta < 2) LogicError("G_BKZ_FP: bad block size"); return G_BKZ_FP(BB, 0, delta, beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/G_LLL_QP.cpp0000644417616742025610000012630714064716022016752 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_START_IMPL static inline void CheckFinite(double *p) { if (!IsFinite(p)) ResourceError("G_LLL_QP: numbers too big...use G_LLL_XD"); } static inline void CheckFinite(quad_float *p) { if (!IsFinite(p)) ResourceError("G_LLL_QP: numbers too big...use G_LLL_XD"); } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } #define TR_BND (NTL_FDOUBLE_PRECISION/2.0) // Just to be safe!! static double max_abs(quad_float *v, long n) { long i; double res, t; res = 0; for (i = 1; i <= n; i++) { t = fabs(v[i].hi); if (t > res) res = t; } return res; } static void RowTransformStart(quad_float *a, long *in_a, long& in_float, long n) { long i; long inf = 1; for (i = 1; i <= n; i++) { in_a[i] = (a[i].hi < TR_BND && a[i].hi > -TR_BND); inf = inf & in_a[i]; } in_float = inf; } static void RowTransformFinish(vec_ZZ& A, quad_float *a, long *in_a) { long n = A.length(); long i; for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); } else { conv(a[i], A(i)); CheckFinite(&a[i]); } } } static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1, quad_float *a, quad_float *b, long *in_a, double& max_a, double max_b, long& in_float) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; double mu; long n = A.length(); long i; conv(mu, MU1); CheckFinite(&mu); if (in_float) { double mu_abs = fabs(mu); if (mu_abs > 0 && max_b > 0 && (mu_abs >= TR_BND || max_b >= TR_BND)) { in_float = 0; } else { max_a += mu_abs*max_b; if (max_a >= TR_BND) in_float = 0; } } if (in_float) { if (mu == 1) { for (i = 1; i <= n; i++) a[i].hi -= b[i].hi; return; } if (mu == -1) { for (i = 1; i <= n; i++) a[i].hi += b[i].hi; return; } if (mu == 0) return; for (i = 1; i <= n; i++) a[i].hi -= mu*b[i].hi; return; } MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi -= b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } sub(A(i), A(i), B(i)); } } return; } if (MU == -1) { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < TR_BND && b[i].hi > -TR_BND) { a[i].hi += b[i].hi; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } add(A(i), A(i), B(i)); } } return; } if (MU == 0) return; double b_bnd = fabs(TR_BND/mu) - 1; if (b_bnd < 0) b_bnd = 0; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { if (in_a[i] && a[i].hi < TR_BND && a[i].hi > -TR_BND && b[i].hi < b_bnd && b[i].hi > -b_bnd) { a[i].hi -= b[i].hi*mu; } else { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } MulSubFrom(A(i), B(i), mu1); } } } } else { for (i = 1; i <= n; i++) { if (in_a[i]) { conv(A(i), a[i].hi); in_a[i] = 0; } mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_QP { public: GivensCache_QP(long m, long n); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; Unique2DArray buf; UniqueArray bl; UniqueArray bv; long bp; }; GivensCache_QP::GivensCache_QP(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; buf.SetDims(sz, n+1); bl.SetLength(sz); bv.SetLength(sz); long i; for (i = 0; i < sz; i++) bl[i] = 0; for (i = 0; i < sz; i++) bv[i] = 0; bp = 0; } void GivensCache_QP::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_QP::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_QP::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_QP::swap() { swap(bl[bp] - 1); } void GivensCache_QP::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_QP::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(quad_float **B1, quad_float **mu, quad_float **aux, long k, long n, GivensCache_QP& cache) { long i, j; quad_float c, s, a, b, t; quad_float *p = mu[k]; quad_float *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { quad_float *cptr = mu[i]; quad_float *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { quad_float *cptr = mu[i]; quad_float *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) LogicError("G_LLL_QP: internal error"); if (k > n) p[k] = 0; for (i = 1; i <= k; i++) CheckFinite(&p[i]); } NTL_TLS_GLOBAL_DECL_INIT(quad_float, red_fudge, (to_quad_float(0))) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); long i; // initial log_red should be <= NTL_DOUBLE_PRECISION-2, // to help ensure stability in G_BKZ_QP1 log_red = NTL_DOUBLE_PRECISION-2; red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_QP: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("G_LLL_QP: too much loss of precision...stop!"); } static long ll_G_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check, quad_float **B1, quad_float **mu, quad_float **aux, long m, long init_k, long &quit, GivensCache_QP& cache) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; quad_float mu1; quad_float t1; double dt1; ZZ T1; quad_float *tp; quad_float half = to_quad_float(0.5); quad_float half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; vec_long in_vec_mem; in_vec_mem.SetLength(n+1); long *in_vec = in_vec_mem.elts(); UniqueArray max_b_store; max_b_store.SetLength(m+1); double *max_b = max_b_store.get(); for (i = 1; i <= m; i++) max_b[i] = max_abs(B1[i], n); long in_float; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_QP: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); Fc1 = 1; RowTransformStart(B1[k], in_vec, in_float, n); } mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); quad_float *mu_k = mu[k]; quad_float *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) mu_k[i] -= mu1*mu_j[i]; } // cout << j << " " << mu[k][j] << " " << mu1 << "\n"; mu_k[j] -= mu1; conv(MU, mu1); RowTransform(B(k), B(j), MU, B1[k], B1[j], in_vec, max_b[k], max_b[j], in_float); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { RowTransformFinish(B(k), B1[k], in_vec); max_b[k] = max_abs(B1[k], n); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; dt1 = max_b[i]; max_b[i] = max_b[i+1]; max_b[i+1] = dt1; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions LogicError("sorry...deep insertions not implemented"); } // end deep insertions // test LLL reduction condition if (k > 1 && sqrt(delta - mu[k][k-1]*mu[k][k-1])*fabs(mu[k-1][k-1]) > fabs(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; dt1 = max_b[k]; max_b[k] = max_b[k-1]; max_b[k-1] = dt1; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { cache.incr(); k++; // cout << "+ " << k << "\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_QP(mat_ZZ& B, mat_ZZ* U, quad_float delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; quad_float s; ZZ MU; quad_float mu1; quad_float t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, n+2); quad_float **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+1, n+1); quad_float **aux = aux_store.get(); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); new_m = ll_G_LLL_QP(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long G_LLL_QP(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_QP: bad delta"); if (deep < 0) LogicError("G_LLL_QP: bad deep"); return G_LLL_QP(B, 0, to_quad_float(delta), deep, check); } long G_LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_QP: bad delta"); if (deep < 0) LogicError("G_LLL_QP: bad deep"); return G_LLL_QP(B, &U, to_quad_float(delta), deep, check); } NTL_TLS_GLOBAL_DECL(vec_quad_float, G_BKZConstant) static void ComputeG_BKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); const quad_float c_PI = to_quad_float("3.141592653589793238462643383279502884197"); const quad_float LogPI = to_quad_float("1.144729885849400174143427351353058711647"); G_BKZConstant.SetLength(beta-1); vec_quad_float Log; Log.SetLength(beta); long i, j, k; quad_float x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_quad_float(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/to_quad_float(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/to_quad_float(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/to_quad_float(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_quad_float, G_BKZThresh) static void ComputeG_BKZThresh(quad_float *c, long beta) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); G_BKZThresh.SetLength(beta-1); long i; quad_float x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = exp(x/to_quad_float(i))*G_BKZConstant(i); if (!IsFinite(&G_BKZThresh(i))) G_BKZThresh(i) = 0; } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_QP status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_QP(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; quad_float t1; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, n+2); quad_float **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+2, n+1); quad_float **aux = aux_store.get(); UniqueArray c_store; c_store.SetLength(m+2); quad_float *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors quad_float cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); quad_float *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); quad_float *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); quad_float *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); quad_float *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); quad_float *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get(); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; quad_float eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("G_BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) LogicError("G_BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) LogicError("G_BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_QP(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_QP: bad delta"); if (beta < 2) LogicError("G_BKZ_QP: bad block size"); return G_BKZ_QP(BB, &UU, to_quad_float(delta), beta, prune, check); } long G_BKZ_QP(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_QP: bad delta"); if (beta < 2) LogicError("G_BKZ_QP: bad block size"); return G_BKZ_QP(BB, 0, to_quad_float(delta), beta, prune, check); } static long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ* UU, quad_float delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; ZZ T1; quad_float *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); quad_float **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, n+2); quad_float **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+2, n+1); quad_float **aux = aux_store.get(); UniqueArray c_store; c_store.SetLength(m+2); quad_float *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors double cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); double *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); double *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); double *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); double *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); double *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get(); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; double eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) { conv(B1[i][j], B(i, j)); CheckFinite(&B1[i][j]); } GivensCache_QP cache(m, n); m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; long clean = 1; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) { c[i] = mu[i][i]*mu[i][i]; CheckFinite(&c[i]); } if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = to_double(c[jj]); utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*to_double(c[t]); ForceToMem(&ctilda[t]); // prevents an infinite loop if (prune > 0 && t > jj) { eta = to_double(G_BKZThresh(t-jj)); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { double t1; t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*to_double(mu[i][t]); } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); quad_float t1; if ((delta-8*red_fudge)*c[jj] > cbar*(1+64/NTL_FDOUBLE_PRECISION)) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("G_BKZ_QP: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) { conv(B1[jj][i], B(jj, i)); CheckFinite(&B1[jj][i]); } if (IsZero(B(jj))) LogicError("G_BKZ_QP: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_QP(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) LogicError("G_BKZ_QP: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_QP // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_QP(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_QP: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_QP: bad delta"); if (beta < 2) LogicError("G_BKZ_QP: bad block size"); return G_BKZ_QP1(BB, &UU, to_quad_float(delta), beta, prune, check); } long G_BKZ_QP1(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_QP: bad delta"); if (beta < 2) LogicError("G_BKZ_QP: bad block size"); return G_BKZ_QP1(BB, 0, to_quad_float(delta), beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/G_LLL_XD.cpp0000644417616742025610000006516314064716022016747 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); if (k > 0) { for (i = 1; i <= n; i++) { mul(T, B(i), mu1); LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { MulSubFrom(A(i), B(i), mu1); } } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_XD { public: GivensCache_XD(long m, long n); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; Unique2DArray buf; UniqueArray bl; UniqueArray bv; long bp; }; GivensCache_XD::GivensCache_XD(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; buf.SetDims(sz, n+1); bl.SetLength(sz); bv.SetLength(sz); long i; for (i = 0; i < sz; i++) bl[i] = 0; for (i = 0; i < sz; i++) bv[i] = 0; bp = 0; } void GivensCache_XD::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_XD::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_XD::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_XD::swap() { swap(bl[bp] - 1); } void GivensCache_XD::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_XD::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(xdouble **B1, xdouble **mu, xdouble **aux, long k, long n, GivensCache_XD& cache) { long i, j; xdouble c, s, a, b, t; xdouble *p = mu[k]; xdouble *pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp[j] = B1[k][j]; long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { xdouble *cptr = mu[i]; xdouble *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*pp[j-1] - s*pp[j]; b = s*pp[j-1] + c*pp[j]; pp[j-1] = a; pp[j] = b; } pp[i] = pp[i]/mu[i][i]; } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p[j] = pp[j]; for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { xdouble *cptr = mu[i]; xdouble *sptr = aux[i]; for (j = n; j > i; j--) { c = cptr[j]; s = sptr[j]; a = c*p[j-1] - s*p[j]; b = s*p[j-1] + c*p[j]; p[j-1] = a; p[j] = b; } p[i] = p[i]/mu[i][i]; } for (j = n; j > k; j--) { a = p[j-1]; b = p[j]; if (b == 0) { c = 1; s = 0; } else if (fabs(b) > fabs(a)) { t = -a/b; s = 1/sqrt(1 + t*t); c = s*t; } else { t = -b/a; c = 1/sqrt(1 + t*t); s = c*t; } p[j-1] = c*a - s*b; p[j] = c; aux[k][j] = s; } if (k > n+1) LogicError("G_LLL_XD: internal error"); if (k > n) p[k] = 0; } NTL_TLS_GLOBAL_DECL_INIT(xdouble, red_fudge, (to_xdouble(0))) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); long i; log_red = long(0.50*NTL_DOUBLE_PRECISION); red_fudge = 1; for (i = log_red; i > 0; i--) red_fudge = red_fudge*0.5; } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); red_fudge = red_fudge * 2; log_red--; cerr << "G_LLL_XD: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("G_LLL_XD: can not continue...sorry"); } static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_G_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check, xdouble **B1, xdouble **mu, xdouble **aux, long m, long init_k, long &quit, GivensCache_XD& cache) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; xdouble *tp; xdouble half = to_xdouble(0.5); xdouble half_plus_fudge = 0.5 + red_fudge; quit = 0; k = init_k; long counter; long trigger_index; long small_trigger; long cnt; long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { t1 = fabs(mu[k][j]); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); half_plus_fudge = 0.5 + red_fudge; cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu[k][j]; if (mu1 >= 0) mu1 = ceil(mu1-half); else mu1 = floor(mu1+half); xdouble *mu_k = mu[k]; xdouble *mu_j = mu[j]; if (mu1 == 1) { for (i = 1; i <= j-1; i++) mu_k[i] -= mu_j[i]; } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) mu_k[i] += mu_j[i]; } else { for (i = 1; i <= j-1; i++) MulSub(mu_k[i], mu_k[i], mu1, mu_j[i]); } mu_k[j] -= mu1; conv(MU, mu1); // cout << j << " " << MU << "\n"; RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1[k][i], B(k, i)); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); tp = B1[i]; B1[i] = B1[i+1]; B1[i+1] = tp; if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions LogicError("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k > 1 && (delta - mu[k][k-1]*mu[k][k-1])*(mu[k-1][k-1])*(mu[k-1][k-1]) > (mu[k][k])*(mu[k][k])) { // swap rows k, k-1 swap(B(k), B(k-1)); tp = B1[k]; B1[k] = B1[k-1]; B1[k-1] = tp; if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; // cout << "- " << k << "\n"; } else { cache.incr(); k++; // cout << "+ " << k << "\n"; } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_XD(mat_ZZ& B, mat_ZZ* U, xdouble delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; xdouble s; ZZ MU; xdouble mu1; xdouble t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+1, n+1); xdouble **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+1, n+2); xdouble **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+1, n+1); xdouble **aux = aux_store.get(); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); GivensCache_XD cache(m, n); new_m = ll_G_LLL_XD(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long G_LLL_XD(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_XD: bad delta"); if (deep < 0) LogicError("G_LLL_XD: bad deep"); return G_LLL_XD(B, 0, to_xdouble(delta), deep, check); } long G_LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_XD: bad delta"); if (deep < 0) LogicError("G_LLL_XD: bad deep"); return G_LLL_XD(B, &U, to_xdouble(delta), deep, check); } NTL_TLS_GLOBAL_DECL(vec_xdouble, G_BKZConstant) static void ComputeG_BKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); const double c_PI = 3.14159265358979323846264338328; const double LogPI = 1.14472988584940017414342735135; G_BKZConstant.SetLength(beta-1); vec_double Log; Log.SetLength(beta); long i, j, k; double x, y; for (j = 1; j <= beta; j++) Log(j) = log(double(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x = x + Log(j); x = x * (1/double(k)); x = exp(x); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x = x + Log(j); x = 0.5*LogPI + x - 2*(k+1)*Log(2); x = x * (2.0/double(i)); x = exp(x); } // Second, we compute y = 2^{2*p/i} y = -(2*p/double(i))*Log(2); y = exp(y); G_BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_xdouble, G_BKZThresh) static void ComputeG_BKZThresh(xdouble *c, long beta) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); G_BKZThresh.SetLength(beta-1); long i; double x; x = 0; for (i = 1; i <= beta-1; i++) { x += log(c[i-1]); G_BKZThresh(i) = xexp(x/double(i))*G_BKZConstant(i); } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_XD status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_XD(mat_ZZ& BB, mat_ZZ* UU, xdouble delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; xdouble t1; ZZ T1; xdouble *tp; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); Unique2DArray B1_store; B1_store.SetDimsFrom1(m+2, n+1); xdouble **B1 = B1_store.get(); // approximates B Unique2DArray mu_store; mu_store.SetDimsFrom1(m+2, n+2); xdouble **mu = mu_store.get(); Unique2DArray aux_store; aux_store.SetDimsFrom1(m+2, n+1); xdouble **aux = aux_store.get(); UniqueArray c_store; c_store.SetLength(m+2); xdouble *c = c_store.get(); // squared lengths of Gramm-Schmidt basis vectors xdouble cbar; UniqueArray ctilda_store; ctilda_store.SetLength(m+2); xdouble *ctilda = ctilda_store.get(); UniqueArray vvec_store; vvec_store.SetLength(m+2); xdouble *vvec = vvec_store.get(); UniqueArray yvec_store; yvec_store.SetLength(m+2); xdouble *yvec = yvec_store.get(); UniqueArray uvec_store; uvec_store.SetLength(m+2); xdouble *uvec = uvec_store.get(); UniqueArray utildavec_store; utildavec_store.SetLength(m+2); xdouble *utildavec = utildavec_store.get(); UniqueArray Deltavec_store; Deltavec_store.SetLength(m+2); long *Deltavec = Deltavec_store.get(); UniqueArray deltavec_store; deltavec_store.SetLength(m+2); long *deltavec = deltavec_store.get(); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; xdouble eta; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1[i][j], B(i, j)); // cerr << "\n"; // cerr << "first G_LLL\n"; GivensCache_XD cache(m, n); m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) c[i] = mu[i][i]*mu[i][i]; if (prune > 0) ComputeG_BKZThresh(&c[jj], kk-jj+1); cbar = c[jj]; utildavec[jj] = uvec[jj] = 1; yvec[jj] = vvec[jj] = 0; Deltavec[jj] = 0; s = t = jj; deltavec[jj] = 1; for (i = jj+1; i <= kk+1; i++) { ctilda[i] = uvec[i] = utildavec[i] = yvec[i] = 0; Deltavec[i] = 0; vvec[i] = 0; deltavec[i] = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } ctilda[t] = ctilda[t+1] + (yvec[t]+utildavec[t])*(yvec[t]+utildavec[t])*c[t]; if (prune > 0 && t > jj) { eta = G_BKZThresh(t-jj); } else eta = 0; if (ctilda[t] < cbar - eta) { if (t > jj) { t--; t1 = 0; for (i = t+1; i <= s; i++) { t1 += utildavec[i]*mu[i][t]; } yvec[t] = t1; t1 = -t1; if (t1 >= 0) t1 = ceil(t1-0.5); else t1 = floor(t1+0.5); utildavec[t] = vvec[t] = t1; Deltavec[t] = 0; if (utildavec[t] > -yvec[t]) deltavec[t] = -1; else deltavec[t] = 1; } else { cbar = ctilda[jj]; for (i = jj; i <= kk; i++) { uvec[i] = utildavec[i]; } } } else { t++; s = max(s, t); if (t < s) Deltavec[t] = -Deltavec[t]; if (Deltavec[t]*deltavec[t] >= 0) Deltavec[t] += deltavec[t]; utildavec[t] = vvec[t] + Deltavec[t]; } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); if ((delta-8*red_fudge)*c[jj] > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec[i] != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("G_BKZ_XD: internal error"); if (s > 0) { // special case NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } // cerr << "special case\n"; new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) LogicError("G_BKZ_XD: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec[i] == 0) continue; conv(MU, uvec[i]); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } for (i = 1; i <= n; i++) conv(B1[jj][i], B(jj, i)); if (IsZero(B(jj))) LogicError("G_BKZ_XD: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_XD(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) LogicError("G_BKZ_XD: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); if (U) swap((*U)(i-1), (*U)(i)); tp = B1[i-1]; B1[i-1] = B1[i]; B1[i] = tp; } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_XD: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_XD // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_XD(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_XD: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_XD(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_XD: bad delta"); if (beta < 2) LogicError("G_BKZ_XD: bad block size"); return G_BKZ_XD(BB, &UU, to_xdouble(delta), beta, prune, check); } long G_BKZ_XD(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_XD: bad delta"); if (beta < 2) LogicError("G_BKZ_XD: bad block size"); return G_BKZ_XD(BB, 0, to_xdouble(delta), beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/G_LLL_RR.cpp0000644417616742025610000006517314064716022016760 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_START_IMPL static void RowTransform(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x - y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); sub(A(i), A(i), T); } } } static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } } class GivensCache_RR { public: GivensCache_RR(long m, long n); void flush(); void selective_flush(long l); void swap(long l); void swap(); void touch(); void incr(); long sz; mat_RR buf; UniqueArray bl; UniqueArray bv; long bp; }; GivensCache_RR::GivensCache_RR(long m, long n) { sz = min(m, n)/10; if (sz < 2) sz = 2; else if (sz > 20) sz = 20; buf.SetDims(sz, n); bl.SetLength(sz); bv.SetLength(sz); long i; for (i = 0; i < sz; i++) bl[i] = 0; for (i = 0; i < sz; i++) bv[i] = 0; bp = 0; } void GivensCache_RR::flush() { long i; for (i = 0; i < sz; i++) bl[i] = 0; } void GivensCache_RR::selective_flush(long l) { long i; for (i = 0; i < sz; i++) if (bl[i] && bv[i] >= l) bl[i] = 0; } void GivensCache_RR::swap(long l) { long k = bl[bp]; long i; i = 0; while (i < sz && bl[i] != l) i++; if (i < sz) { bl[bp] = l; bl[i] = k; } else bl[bp] = l; selective_flush(l); } void GivensCache_RR::swap() { swap(bl[bp] - 1); } void GivensCache_RR::touch() { long k = bl[bp]; bl[bp] = 0; selective_flush(k); } void GivensCache_RR::incr() { long k = bl[bp]; long k1 = k+1; long i; i = 0; while (i < sz && bl[i] != k1) i++; if (i < sz) { bp = i; return; } i = 0; while (i < sz && bl[i] != 0) i++; if (i < sz) { bp = i; return; } long max_val = 0; long max_index = 0; for (i = 0; i < sz; i++) { long t = labs(bl[i]-k1); if (t > max_val) { max_val = t; max_index = i; } } bp = max_index; bl[max_index] = 0; } static void GivensComputeGS(mat_RR& B1, mat_RR& mu, mat_RR& aux, long k, long n, GivensCache_RR& cache) { long i, j; RR c, s, a, b, t; RR T1, T2; vec_RR& p = mu(k); vec_RR& pp = cache.buf[cache.bp]; if (!cache.bl[cache.bp]) { for (j = 1; j <= n; j++) pp(j) = B1(k,j); long backoff; backoff = k/4; if (backoff < 2) backoff = 2; else if (backoff > cache.sz + 2) backoff = cache.sz + 2; long ub = k-(backoff-1); for (i = 1; i < ub; i++) { vec_RR& cptr = mu(i); vec_RR& sptr = aux(i); for (j = n; j > i; j--) { c = cptr(j); s = sptr(j); // a = c*pp(j-1) - s*pp(j); mul(T1, c, pp(j-1)); mul(T2, s, pp(j)); sub(a, T1, T2); // b = s*pp(j-1) + c*pp(j); mul(T1, s, pp(j-1)); mul(T2, c, pp(j)); add(b, T1, T2); pp(j-1) = a; pp(j) = b; } div(pp(i), pp(i), mu(i,i)); } cache.bl[cache.bp] = k; cache.bv[cache.bp] = k-backoff; } for (j = 1; j <= n; j++) p(j) = pp(j); for (i = max(cache.bv[cache.bp]+1, 1); i < k; i++) { vec_RR& cptr = mu(i); vec_RR& sptr = aux(i); for (j = n; j > i; j--) { c = cptr(j); s = sptr(j); // a = c*p(j-1) - s*p(j); mul(T1, c, p(j-1)); mul(T2, s, p(j)); sub(a, T1, T2); // b = s*p(j-1) + c*p(j); mul(T1, s, p(j-1)); mul(T2, c, p(j)); add(b, T1, T2); p(j-1) = a; p(j) = b; } div(p(i), p(i), mu(i,i)); } for (j = n; j > k; j--) { a = p(j-1); b = p(j); if (b == 0) { c = 1; s = 0; } else { abs(T1, b); abs(T2, a); if (T1 > T2) { // t = -a/b; div(T1, a, b); negate(t, T1); // s = 1/sqrt(1 + t*t); sqr(T1, t); add(T1, T1, 1); SqrRoot(T1, T1); inv(s, T1); // c = s*t; mul(c, s, t); } else { // t = -b/a; div(T1, b, a); negate(t, T1); // c = 1/sqrt(1 + t*t); sqr(T1, t); add(T1, T1, 1); SqrRoot(T1, T1); inv(c, T1); // s = c*t; mul(s, c, t); } } // p(j-1) = c*a - s*b; mul(T1, c, a); mul(T2, s, b); sub(p(j-1), T1, T2); p(j) = c; aux(k,j) = s; } if (k > n+1) LogicError("G_LLL_RR: internal error"); if (k > n) p(k) = 0; } NTL_TLS_GLOBAL_DECL(RR, red_fudge) static NTL_CHEAP_THREAD_LOCAL long log_red = 0; static void init_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); log_red = long(0.50*RR::precision()); power2(red_fudge, -log_red); } static void inc_red_fudge() { NTL_TLS_GLOBAL_ACCESS(red_fudge); mul(red_fudge, red_fudge, 2); log_red--; cerr << "G_LLL_RR: warning--relaxing reduction (" << log_red << ")\n"; if (log_red < 4) ResourceError("G_LLL_RR: can not continue...sorry"); } static NTL_CHEAP_THREAD_LOCAL long verbose = 0; static NTL_CHEAP_THREAD_LOCAL unsigned long NumSwaps = 0; static NTL_CHEAP_THREAD_LOCAL double StartTime = 0; static NTL_CHEAP_THREAD_LOCAL double LastTime = 0; static void G_LLLStatus(long max_k, double t, long m, const mat_ZZ& B) { cerr << "---- G_LLL_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, t-StartTime); cerr << ", stage: " << max_k; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = t; } static long ll_G_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check, mat_RR& B1, mat_RR& mu, mat_RR& aux, long m, long init_k, long &quit, GivensCache_RR& cache) { NTL_TLS_GLOBAL_ACCESS(red_fudge); long n = B.NumCols(); long i, j, k, Fc1; ZZ MU; RR mu1, t1, t2, cc; ZZ T1; quit = 0; k = init_k; long counter; long trigger_index; long small_trigger; long cnt; RR half; conv(half, 0.5); RR half_plus_fudge; add(half_plus_fudge, half, red_fudge); long max_k = 0; double tt; cache.flush(); while (k <= m) { if (k > max_k) { max_k = k; } if (verbose) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_LLLStatus(max_k, tt, m, B); } GivensComputeGS(B1, mu, aux, k, n, cache); counter = 0; trigger_index = k; small_trigger = 0; cnt = 0; do { // size reduction counter++; if (counter > 10000) { cerr << "G_LLL_XD: warning--possible infinite loop\n"; counter = 0; } Fc1 = 0; for (j = k-1; j >= 1; j--) { abs(t1, mu(k,j)); if (t1 > half_plus_fudge) { if (!Fc1) { if (j > trigger_index || (j == trigger_index && small_trigger)) { cnt++; if (cnt > 10) { inc_red_fudge(); add(half_plus_fudge, half, red_fudge); cnt = 0; } } trigger_index = j; small_trigger = (t1 < 4); } Fc1 = 1; mu1 = mu(k,j); if (sign(mu1) >= 0) { sub(mu1, mu1, half); ceil(mu1, mu1); } else { add(mu1, mu1, half); floor(mu1, mu1); } if (mu1 == 1) { for (i = 1; i <= j-1; i++) sub(mu(k,i), mu(k,i), mu(j,i)); } else if (mu1 == -1) { for (i = 1; i <= j-1; i++) add(mu(k,i), mu(k,i), mu(j,i)); } else { for (i = 1; i <= j-1; i++) { mul(t2, mu1, mu(j,i)); sub(mu(k,i), mu(k,i), t2); } } conv(MU, mu1); sub(mu(k,j), mu(k,j), mu1); RowTransform(B(k), B(j), MU); if (U) RowTransform((*U)(k), (*U)(j), MU); } } if (Fc1) { for (i = 1; i <= n; i++) conv(B1(k, i), B(k, i)); cache.touch(); GivensComputeGS(B1, mu, aux, k, n, cache); } } while (Fc1); if (check && (*check)(B(k))) quit = 1; if (IsZero(B(k))) { for (i = k; i < m; i++) { // swap i, i+1 swap(B(i), B(i+1)); swap(B1(i), B1(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } cache.flush(); m--; if (quit) break; continue; } if (quit) break; if (deep > 0) { // deep insertions LogicError("sorry...deep insertions not implemented"); } // end deep insertions // test G_LLL reduction condition if (k <= 1) { cache.incr(); k++; } else { sqr(t1, mu(k,k-1)); sub(t1, delta, t1); sqr(t2, mu(k-1,k-1)); mul(t1, t1, t2); sqr(t2, mu(k, k)); if (t1 > t2) { // swap rows k, k-1 swap(B(k), B(k-1)); swap(B1(k), B1(k-1)); if (U) swap((*U)(k), (*U)(k-1)); cache.swap(); k--; NumSwaps++; } else { cache.incr(); k++; } } } if (verbose) { G_LLLStatus(m+1, GetTime(), m, B); } return m; } static long G_LLL_RR(mat_ZZ& B, mat_ZZ* U, const RR& delta, long deep, LLLCheckFct check) { long m = B.NumRows(); long n = B.NumCols(); long i, j; long new_m, dep, quit; RR s; ZZ MU; RR mu1; RR t1; ZZ T1; init_red_fudge(); if (U) ident(*U, m); mat_RR B1; // approximates B B1.SetDims(m, n); mat_RR mu; mu.SetDims(m, n+1); mat_RR aux; aux.SetDims(m, n); for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); GivensCache_RR cache(m, n); new_m = ll_G_LLL_RR(B, U, delta, deep, check, B1, mu, aux, m, 1, quit, cache); dep = m - new_m; m = new_m; if (dep > 0) { // for consistency, we move all of the zero rows to the front for (i = 0; i < m; i++) { swap(B(m+dep-i), B(m-i)); if (U) swap((*U)(m+dep-i), (*U)(m-i)); } } return m; } long G_LLL_RR(mat_ZZ& B, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_RR: bad delta"); if (deep < 0) LogicError("G_LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return G_LLL_RR(B, 0, Delta, deep, check); } long G_LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta, long deep, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_LLL_RR: bad delta"); if (deep < 0) LogicError("G_LLL_RR: bad deep"); RR Delta; conv(Delta, delta); return G_LLL_RR(B, &U, Delta, deep, check); } NTL_TLS_GLOBAL_DECL(vec_RR, G_BKZConstant) static void ComputeG_BKZConstant(long beta, long p) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); RR c_PI; ComputePi(c_PI); RR LogPI = log(c_PI); G_BKZConstant.SetLength(beta-1); vec_RR Log; Log.SetLength(beta); long i, j, k; RR x, y; for (j = 1; j <= beta; j++) Log(j) = log(to_RR(j)); for (i = 1; i <= beta-1; i++) { // First, we compute x = gamma(i/2)^{2/i} k = i/2; if ((i & 1) == 0) { // i even x = 0; for (j = 1; j <= k; j++) x += Log(j); x = exp(x/k); } else { // i odd x = 0; for (j = k + 2; j <= 2*k + 2; j++) x += Log(j); x += 0.5*LogPI - 2*(k+1)*Log(2); x = exp(2*x/i); } // Second, we compute y = 2^{2*p/i} y = exp(-(2*p/to_RR(i))*Log(2)); G_BKZConstant(i) = x*y/c_PI; } } NTL_TLS_GLOBAL_DECL(vec_RR, G_BKZThresh) static void ComputeG_BKZThresh(RR *c, long beta) { NTL_TLS_GLOBAL_ACCESS(G_BKZConstant); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); G_BKZThresh.SetLength(beta-1); long i; RR x; RR t1; x = 0; for (i = 1; i <= beta-1; i++) { log(t1, c[i-1]); add(x, x, t1); div(t1, x, i); exp(t1, t1); mul(G_BKZThresh(i), t1, G_BKZConstant(i)); } } static void G_BKZStatus(double tt, double enum_time, unsigned long NumIterations, unsigned long NumTrivial, unsigned long NumNonTrivial, unsigned long NumNoOps, long m, const mat_ZZ& B) { cerr << "---- G_BKZ_RR status ----\n"; cerr << "elapsed time: "; PrintTime(cerr, tt-StartTime); cerr << ", enum time: "; PrintTime(cerr, enum_time); cerr << ", iter: " << NumIterations << "\n"; cerr << "triv: " << NumTrivial; cerr << ", nontriv: " << NumNonTrivial; cerr << ", no ops: " << NumNoOps; cerr << ", rank: " << m; cerr << ", swaps: " << NumSwaps << "\n"; ZZ t1; long i; double prodlen = 0; for (i = 1; i <= m; i++) { InnerProduct(t1, B(i), B(i)); if (!IsZero(t1)) prodlen += log(t1); } cerr << "log of prod of lengths: " << prodlen/(2.0*log(2.0)) << "\n"; if (LLLDumpFile) { cerr << "dumping to " << LLLDumpFile << "..."; ofstream f; OpenWrite(f, LLLDumpFile); f << "["; for (i = 1; i <= m; i++) { f << B(i) << "\n"; } f << "]\n"; f.close(); cerr << "\n"; } LastTime = tt; } static long G_BKZ_RR(mat_ZZ& BB, mat_ZZ* UU, const RR& delta, long beta, long prune, LLLCheckFct check) { NTL_TLS_GLOBAL_ACCESS(red_fudge); NTL_TLS_GLOBAL_ACCESS(G_BKZThresh); long m = BB.NumRows(); long n = BB.NumCols(); long m_orig = m; long i, j; ZZ MU; RR t1, t2; ZZ T1; init_red_fudge(); mat_ZZ B; B = BB; B.SetDims(m+1, n); mat_RR B1; B1.SetDims(m+1, n); mat_RR mu; mu.SetDims(m+1, n+1); mat_RR aux; aux.SetDims(m+1, n); vec_RR c; c.SetLength(m+1); RR cbar; vec_RR ctilda; ctilda.SetLength(m+1); vec_RR vvec; vvec.SetLength(m+1); vec_RR yvec; yvec.SetLength(m+1); vec_RR uvec; uvec.SetLength(m+1); vec_RR utildavec; utildavec.SetLength(m+1); vec_long Deltavec; Deltavec.SetLength(m+1); vec_long deltavec; deltavec.SetLength(m+1); mat_ZZ Ulocal; mat_ZZ *U; if (UU) { Ulocal.SetDims(m+1, m); for (i = 1; i <= m; i++) conv(Ulocal(i, i), 1); U = &Ulocal; } else U = 0; long quit; long new_m; long z, jj, kk; long s, t; long h; for (i = 1; i <=m; i++) for (j = 1; j <= n; j++) conv(B1(i, j), B(i, j)); // cerr << "\n"; // cerr << "first G_LLL\n"; GivensCache_RR cache(m, n); m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, m, 1, quit, cache); double tt; double enum_time = 0; unsigned long NumIterations = 0; unsigned long NumTrivial = 0; unsigned long NumNonTrivial = 0; unsigned long NumNoOps = 0; long verb = verbose; verbose = 0; if (m < m_orig) { for (i = m_orig+1; i >= m+2; i--) { // swap i, i-1 swap(B(i), B(i-1)); if (U) swap((*U)(i), (*U)(i-1)); } } long clean = 1; if (!quit && m > 1) { // cerr << "continuing\n"; if (beta > m) beta = m; if (prune > 0) ComputeG_BKZConstant(beta, prune); z = 0; jj = 0; while (z < m-1) { jj++; kk = min(jj+beta-1, m); if (jj == m) { jj = 1; kk = beta; clean = 1; } if (verb) { tt = GetTime(); if (tt > LastTime + LLLStatusInterval) G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // ENUM double tt1; if (verb) { tt1 = GetTime(); } for (i = jj; i <= kk; i++) sqr(c(i), mu(i,i)); if (prune > 0) ComputeG_BKZThresh(&c(jj), kk-jj+1); cbar = c(jj); conv(utildavec(jj), 1); conv(uvec(jj), 1); conv(yvec(jj), 0); conv(vvec(jj), 0); Deltavec(jj) = 0; s = t = jj; deltavec(jj) = 1; for (i = jj+1; i <= kk+1; i++) { conv(ctilda(i), 0); conv(uvec(i), 0); conv(utildavec(i), 0); conv(yvec(i), 0); Deltavec(i) = 0; conv(vvec(i), 0); deltavec(i) = 1; } long enum_cnt = 0; while (t <= kk) { if (verb) { enum_cnt++; if (enum_cnt > 100000) { enum_cnt = 0; tt = GetTime(); if (tt > LastTime + LLLStatusInterval) { enum_time += tt - tt1; tt1 = tt; G_BKZStatus(tt, enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } } } add(t1, yvec(t), utildavec(t)); sqr(t1, t1); mul(t1, t1, c(t)); add(ctilda(t), ctilda(t+1), t1); if (prune > 0 && t > jj) sub(t1, cbar, G_BKZThresh(t-jj)); else t1 = cbar; if (ctilda(t) jj) { t--; clear(t1); for (i = t+1; i <= s; i++) { mul(t2, utildavec(i), mu(i,t)); add(t1, t1, t2); } yvec(t) = t1; negate(t1, t1); if (sign(t1) >= 0) { sub(t1, t1, 0.5); ceil(t1, t1); } else { add(t1, t1, 0.5); floor(t1, t1); } utildavec(t) = t1; vvec(t) = t1; Deltavec(t) = 0; negate(t1, t1); if (t1 < yvec(t)) deltavec(t) = -1; else deltavec(t) = 1; } else { cbar = ctilda(jj); for (i = jj; i <= kk; i++) { uvec(i) = utildavec(i); } } } else { t++; s = max(s, t); if (t < s) Deltavec(t) = -Deltavec(t); if (Deltavec(t)*deltavec(t) >= 0) Deltavec(t) += deltavec(t); add(utildavec(t), vvec(t), Deltavec(t)); } } if (verb) { tt1 = GetTime() - tt1; enum_time += tt1; } NumIterations++; h = min(kk+1, m); mul(t1, red_fudge, -8); add(t1, t1, delta); mul(t1, t1, c(jj)); if (t1 > cbar) { clean = 0; // we treat the case that the new vector is b_s (jj < s <= kk) // as a special case that appears to occur most of the time. s = 0; for (i = jj+1; i <= kk; i++) { if (uvec(i) != 0) { if (s == 0) s = i; else s = -1; } } if (s == 0) LogicError("G_BKZ_RR: internal error"); if (s > 0) { // special case // cerr << "special case\n"; NumTrivial++; for (i = s; i > jj; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, jj, quit, cache); if (new_m != h) LogicError("G_BKZ_RR: internal error"); if (quit) break; } else { // the general case NumNonTrivial++; for (i = 1; i <= n; i++) conv(B(m+1, i), 0); if (U) { for (i = 1; i <= m_orig; i++) conv((*U)(m+1, i), 0); } for (i = jj; i <= kk; i++) { if (uvec(i) == 0) continue; conv(MU, uvec(i)); RowTransform2(B(m+1), B(i), MU); if (U) RowTransform2((*U)(m+1), (*U)(i), MU); } for (i = m+1; i >= jj+1; i--) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } for (i = 1; i <= n; i++) conv(B1(jj, i), B(jj, i)); if (IsZero(B(jj))) LogicError("G_BKZ_RR: internal error"); // remove linear dependencies // cerr << "general case\n"; new_m = ll_G_LLL_RR(B, U, delta, 0, 0, B1, mu, aux, kk+1, jj, quit, cache); if (new_m != kk) LogicError("G_BKZ_RR: internal error"); // remove zero vector for (i = kk+2; i <= m+1; i++) { // swap i, i-1 swap(B(i-1), B(i)); swap(B1(i-1), B1(i)); if (U) swap((*U)(i-1), (*U)(i)); } quit = 0; if (check) { for (i = 1; i <= kk; i++) if ((*check)(B(i))) { quit = 1; break; } } if (quit) break; if (h > kk) { // extend reduced basis new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_RR: internal error"); if (quit) break; } } z = 0; } else { // G_LLL_RR // cerr << "progress\n"; NumNoOps++; if (!clean) { new_m = ll_G_LLL_RR(B, U, delta, 0, check, B1, mu, aux, h, h, quit, cache); if (new_m != h) LogicError("G_BKZ_RR: internal error"); if (quit) break; } z++; } } } if (verb) { G_BKZStatus(GetTime(), enum_time, NumIterations, NumTrivial, NumNonTrivial, NumNoOps, m, B); } // clean up if (m_orig > m) { // for consistency, we move zero vectors to the front for (i = m+1; i <= m_orig; i++) { swap(B(i), B(i+1)); if (U) swap((*U)(i), (*U)(i+1)); } for (i = 0; i < m; i++) { swap(B(m_orig-i), B(m-i)); if (U) swap((*U)(m_orig-i), (*U)(m-i)); } } B.SetDims(m_orig, n); BB = B; if (U) { U->SetDims(m_orig, m_orig); *UU = *U; } return m; } long G_BKZ_RR(mat_ZZ& BB, mat_ZZ& UU, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_RR: bad delta"); if (beta < 2) LogicError("G_BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return G_BKZ_RR(BB, &UU, Delta, beta, prune, check); } long G_BKZ_RR(mat_ZZ& BB, double delta, long beta, long prune, LLLCheckFct check, long verb) { verbose = verb; NumSwaps = 0; if (verbose) { StartTime = GetTime(); LastTime = StartTime; } if (delta < 0.50 || delta >= 1) LogicError("G_BKZ_RR: bad delta"); if (beta < 2) LogicError("G_BKZ_RR: bad block size"); RR Delta; conv(Delta, delta); return G_BKZ_RR(BB, 0, Delta, beta, prune, check); } NTL_END_IMPL ntl-11.5.1/src/thread.cpp0000644417616742025610000000072514064716022016723 0ustar gid-shoupvpug-gid-shoupv #include #ifdef NTL_THREADS #include #include #endif NTL_START_IMPL const std::string& CurrentThreadID() { NTL_TLS_LOCAL(std::string, ID); static NTL_CHEAP_THREAD_LOCAL bool initialized = false; if (!initialized) { #ifdef NTL_THREADS std::stringstream ss; ss << std::this_thread::get_id(); ID = ss.str(); #else ID = "0"; #endif initialized = true; } return ID; } NTL_END_IMPL ntl-11.5.1/src/BasicThreadPool.cpp0000644417616742025610000000123414064716022020453 0ustar gid-shoupvpug-gid-shoupv #include // make a global symbol, just to supress warnings int _ntl_BasicThreadPool_dummy_symbol = 0; #ifdef NTL_THREAD_BOOST NTL_START_IMPL NTL_TLS_GLOBAL_DECL(UniquePtr, NTLThreadPool_stg) NTL_CHEAP_THREAD_LOCAL BasicThreadPool *NTLThreadPool_ptr = 0; void ResetThreadPool(BasicThreadPool *pool) { NTL_TLS_GLOBAL_ACCESS(NTLThreadPool_stg); NTLThreadPool_stg.reset(pool); NTLThreadPool_ptr = pool; } BasicThreadPool *ReleaseThreadPool() { NTL_TLS_GLOBAL_ACCESS(NTLThreadPool_stg); BasicThreadPool *pool = NTLThreadPool_stg.release(); NTLThreadPool_ptr = 0; return pool; } NTL_END_IMPL #endif ntl-11.5.1/src/MatPrime.cpp0000644417616742025610000002450614064716022017175 0ustar gid-shoupvpug-gid-shoupv #include NTL_START_IMPL MatPrimeTablesType MatPrimeTables; // a truly GLOBAL variable, shared among all threads // For now, we use the same logic as for IsFFTPrime, // which is good enough static long IsMatPrime(long n) { long m, x, y, z; long j, k; if (n <= 1 || n >= NTL_SP_BOUND) return 0; if (n % 2 == 0) return 0; if (n % 3 == 0) return 0; if (n % 5 == 0) return 0; if (n % 7 == 0) return 0; m = n - 1; k = 0; while ((m & 1) == 0) { m = m >> 1; k++; } for (;;) { x = RandomBnd(n); if (x == 0) continue; z = PowerMod(x, m, n); if (z == 1) continue; x = z; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; if (j == k) break; } /* x^{2^k} = 1 mod n, x^{2^{k-1}} = -1 mod n */ long TrialBound; TrialBound = m >> k; if (TrialBound > 0) { if (!ProbPrime(n, 5)) return 0; /* we have to do trial division by special numbers */ TrialBound = SqrRoot(TrialBound); long a, b; for (a = 1; a <= TrialBound; a++) { b = (a << k) + 1; if (n % b == 0) return 0; } } return 1; } static void NextMatPrime(long& q, long index) { static long m = NTL_MatPrime_NBITS-1; static long k = 0; // m and k are truly GLOBAL variables, shared among // all threads. Access is protected by a critical section // guarding MatPrimeTables static long last_index = -1; static long last_m = 0; static long last_k = 0; if (index == last_index) { // roll back m and k...part of a simple error recovery // strategy if an exception was thrown in the last // invocation of UseMatPrime...probably of academic // interest only m = last_m; k = last_k; } else { last_index = index; last_m = m; last_k = k; } long cand; for (;;) { if (k == 0) { m--; if (m < 3) ResourceError("ran out of matrix primes"); k = 1L << (NTL_MatPrime_NBITS-m-2); } k--; cand = (1L << (NTL_MatPrime_NBITS-1)) + (k << (m+1)) + (1L << m) + 1; if (!IsMatPrime(cand)) continue; q = cand; return; } } void InitMatPrimeInfo(MatPrimeInfo& info, long q) { info.q = q; info.context = zz_pContext(q); } void UseMatPrime(long index) { if (index < 0) LogicError("invalid matrix prime index"); if (index >= NTL_MAX_MATPRIMES) ResourceError("matrix prime index too large"); if (index+1 >= NTL_NSP_BOUND) ResourceError("matrix prime index too large"); // largely acacedemic, but it is a convenient assumption do { // NOTE: thread safe lazy init MatPrimeTablesType::Builder bld(MatPrimeTables, index+1); long amt = bld.amt(); if (!amt) break; long first = index+1-amt; // initialize entries first..index long i; for (i = first; i <= index; i++) { UniquePtr info; info.make(); long q, w; NextMatPrime(q, i); InitMatPrimeInfo(*info, q); bld.move(info); } } while (0); } #ifndef NTL_MatPrime_HALF_SIZE_STRATEGY void build(MatPrime_crt_helper& H, const ZZ& P) { ZZ B, M, M1, M2, M3; long n, i; long q, t; mulmod_t qinv; sqr(B, P); mul(B, B, NTL_MatPrimeLimit); LeftShift(B, B, NTL_MatPrimeFudge); set(M); n = 0; while (M <= B) { UseMatPrime(n); q = GetMatPrime(n); n++; mul(M, M, q); } double fn = double(n); if (8.0*fn*(fn+48) > NTL_FDOUBLE_PRECISION) ResourceError("modulus too big"); H.NumPrimes = n; H.sz = P.size(); H.prime.SetLength(n); H.prime_recip.SetLength(n); H.u.SetLength(n); H.uqinv.SetLength(n); H.ZZ_red_struct.SetLength(n); H.coeff.SetSize(n, P.size()); H.montgomery_struct.init(P, ZZ(n) << NTL_MatPrime_NBITS); ZZ qq, rr; DivRem(qq, rr, M, P); NegateMod(H.MinusMModP, rr, P); H.montgomery_struct.adjust(H.MinusMModP); for (i = 0; i < n; i++) { q = GetMatPrime(i); qinv = MatPrimeTables[i]->context.ModulusInverse(); long tt = rem(qq, q); mul(M2, P, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); // montgomery H.montgomery_struct.adjust(M2); H.prime[i] = q; H.prime_recip[i] = 1/double(q); H.u[i] = t; H.uqinv[i] = PrepMulModPrecon(H.u[i], q, qinv); H.ZZ_red_struct[i] = &MatPrimeTables[i]->context.ZZ_red_struct(); H.coeff[i] = M2; } H.cost = double(H.sz)*double(n); } void reduce(const MatPrime_crt_helper& H, const ZZ& value, MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch) { long n = H.NumPrimes; const sp_ZZ_reduce_struct *const *red_struct = H.ZZ_red_struct.elts(); for (long i = 0; i < n; i++) remainders[i] = red_struct[i]->rem(value); } void reconstruct(const MatPrime_crt_helper& H, ZZ& value, const MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch) { ZZ& t = scratch.t; long nprimes = H.NumPrimes; const long *u = H.u.elts(); const long *prime = H.prime.elts(); const mulmod_precon_t *uqinv = H.uqinv.elts(); const double *prime_recip = H.prime_recip.elts(); double y = 0.0; QuickAccumBegin(t, H.sz); for (long i = 0; i < nprimes; i++) { long r = MulModPrecon(remainders[i], u[i], prime[i], uqinv[i]); y += double(r)*prime_recip[i]; QuickAccumMulAdd(t, H.coeff[i], r); } long q = long(y + 0.5); QuickAccumMulAdd(t, H.MinusMModP, q); QuickAccumEnd(t); // montgomery H.montgomery_struct.eval(value, t); } #else void build(MatPrime_crt_helper& H, const ZZ& P) { ZZ B, M, M1, M2, M3; long n, i, j; long q, t; mulmod_t qinv; sqr(B, P); mul(B, B, NTL_MatPrimeLimit); LeftShift(B, B, NTL_MatPrimeFudge); set(M); n = 0; while (M <= B) { UseMatPrime(n); q = GetMatPrime(n); n++; mul(M, M, q); } double fn = double(n); if (8.0*fn*(fn+48) > NTL_FDOUBLE_PRECISION) ResourceError("modulus too big"); long n_half_ceil = (n+1)/2; H.NumPrimes = n; H.sz = P.size(); H.prime.SetLength(n); H.prime_recip.SetLength(n); H.u.SetLength(n); H.uqinv.SetLength(n); H.red_struct.SetLength(n); H.ZZ_red_struct.SetLength(n_half_ceil); H.coeff.SetSize(n_half_ceil, P.size()); H.montgomery_struct.init(P, ZZ(n) << (2*NTL_MatPrime_NBITS)); for (i = 0; i < n; i++) { q = GetMatPrime(i); qinv = MatPrimeTables[i]->context.ModulusInverse(); div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); // = (M/q)^{-1} rem q H.prime[i] = q; H.prime_recip[i] = 1/double(q); H.u[i] = t; H.uqinv[i] = PrepMulModPrecon(H.u[i], q, qinv); H.red_struct[i] = MatPrimeTables[i]->context.red_struct(); } ZZ qq, rr; DivRem(qq, rr, M, P); NegateMod(H.MinusMModP, rr, P); H.montgomery_struct.adjust(H.MinusMModP); for (i = 0, j = 0; i < n; i += 2, j++) { q = GetMatPrime(i); if (i+1 < n) q *= GetMatPrime(i+1); long tt = rem(qq, q); mul(M2, P, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p // montgomery H.montgomery_struct.adjust(M2); H.ZZ_red_struct[j].build(q); H.coeff[j] = M2; } H.cost = double(H.sz)*double(n_half_ceil); } void reduce(const MatPrime_crt_helper& H, const ZZ& value, MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch) { long n = H.NumPrimes; const sp_ZZ_reduce_struct *ZZ_red_struct = H.ZZ_red_struct.elts(); const sp_reduce_struct *red_struct = H.red_struct.elts(); const long *prime = H.prime.elts(); long i = 0, j = 0; for (; i <= n-2; i += 2, j++) { unsigned long t = ZZ_red_struct[j].rem(value); remainders[i] = rem(t, prime[i], red_struct[i]); remainders[i+1] = rem(t, prime[i+1], red_struct[i+1]); } if (i < n) { remainders[i] = ZZ_red_struct[j].rem(value); } } void reconstruct(const MatPrime_crt_helper& H, ZZ& value, const MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch) { ZZ& t = scratch.t; long nprimes = H.NumPrimes; const long *u = H.u.elts(); const long *prime = H.prime.elts(); const mulmod_precon_t *uqinv = H.uqinv.elts(); const double *prime_recip = H.prime_recip.elts(); double y = 0.0; QuickAccumBegin(t, H.sz); long i = 0, j = 0; for (; i <= nprimes-2; i += 2, j++) { long r0 = MulModPrecon(remainders[i], u[i], prime[i], uqinv[i]); long r1 = MulModPrecon(remainders[i+1], u[i+1], prime[i+1], uqinv[i+1]); y += double(r0)*prime_recip[i] + double(r1)*prime_recip[i+1]; long r = r0*prime[i+1] + r1*prime[i]; QuickAccumMulAdd(t, H.coeff[j], r); } if (i < nprimes) { long r = MulModPrecon(remainders[i], u[i], prime[i], uqinv[i]); y += double(r)*prime_recip[i]; QuickAccumMulAdd(t, H.coeff[j], r); } long q = long(y + 0.5); QuickAccumMulAdd(t, H.MinusMModP, q); QuickAccumEnd(t); // montgomery H.montgomery_struct.eval(value, t); } #endif // Facillitates PIMPL in ZZ_p.h void MatPrime_crt_helper_deleter(MatPrime_crt_helper* p) { delete p; } NTL_END_IMPL #if 0 NTL_CLIENT int main() { ZZ P; RandomLen(P, 8000); MatPrime_crt_helper H; build(H, P); MatPrime_crt_helper_scratch scratch; long nprimes = H.GetNumPrimes(); cerr << nprimes << "\n"; ZZ a, b, c, d, e; RandomBnd(a, P); RandomBnd(b, P); RandomBnd(c, P); RandomBnd(d, P); e = (a*b + c*d) % P; Vec avec, bvec, cvec, dvec, evec; avec.SetLength(nprimes); bvec.SetLength(nprimes); cvec.SetLength(nprimes); dvec.SetLength(nprimes); evec.SetLength(nprimes); reduce(H, a, avec.elts(), scratch); reduce(H, b, bvec.elts(), scratch); reduce(H, c, cvec.elts(), scratch); reduce(H, d, dvec.elts(), scratch); for (long i = 0; i < nprimes; i++) { long q = GetMatPrime(i); evec[i] = AddMod(MulMod(avec[i], bvec[i], q), MulMod(cvec[i], dvec[i], q), q); } ZZ e1; reconstruct(H, e1, evec.elts(), scratch); if (e == e1) cerr << "PASS\n"; else cerr << "FAIL\n"; } #endif ntl-11.5.1/src/pd_FFT.cpp0000644417616742025610000007054214064716022016562 0ustar gid-shoupvpug-gid-shoupv // The configure script should define NTL_FP_CONTRACT_OFF // for icc via the NOCONTRACT variable #ifdef NTL_FP_CONTRACT_OFF #pragma fp_contract(off) #endif #include #ifdef NTL_ENABLE_AVX_FFT // The configure script tries to prevent this, but we // double check here. Note that while it is strongly // discouraged, other parts of NTL probably work even with // "fast math"; however, quad_float will definitely break. #if (defined(__GNUC__) && __FAST_MATH__) #error "do not compile pd_FFT.cpp with -ffast-math!!" #endif #include #include #include #if (defined(__GNUC__) && __FAST_MATH__) #error "do not compile pd_FFT.cpp with -ffast-math!!" #endif #if (NTL_FMA_DETECTED && !defined(NTL_CONTRACTION_FIXED)) #error "contraction not fixed" #endif NTL_START_IMPL #define NTL_CSR_NEAREST (0x00000000) #define NTL_CSR_DOWN (0x00002000) #define NTL_CSR_UP (0x00004000) #define NTL_CSR_TRUNC (0x00006000) #define NTL_CSR_MASK (0x00006000) CSRPush::CSRPush() { // save current register value reg = _mm_getcsr(); // set rounding mode to "down" _mm_setcsr((reg & ~NTL_CSR_MASK) | NTL_CSR_DOWN); } CSRPush::~CSRPush() { _mm_setcsr(reg); } void pd_LazyPrepMulModPrecon_impl(double *bninv, const double *b, double n, long len) { for (long i = 0; i < len; i++) bninv[i] = b[i]/n; } template pd pd_LazyReduce1(pd a, double q) { return correct_excess(a, q); } template pd pd_LazyReduce2(pd a, double q) { return correct_excess(a, 2*q); } // inputs in [0, 2*n), output in [0, 4*n) template pd pd_LazyAddMod(pd a, pd b, double n) { return a+b; } // inputs in [0, 2*n), output in [0, 4*n) template pd pd_LazySubMod(pd a, pd b, double n) { return a-b+2*n; } // inputs in [0, 2*n), output in [0, 2*n) template pd pd_LazyAddMod2(pd a, pd b, double n) { pd r = a+b; return correct_excess(r, 2*n); } // inputs in [0, 2*n), output in [0, 2*n) template pd pd_LazySubMod2(pd a, pd b, double n) { pd r = a-b; return correct_deficit(r, 2*n); } // inputs in [0, 4*n), output in [0, 4*n) template pd pd_LazyAddMod4(pd a, pd b, double n) { pd r = a+b; return correct_excess(r, 4*n); } // inputs in [0, 4*n), output in [0, 4*n) template pd pd_LazySubMod4(pd a, pd b, double n) { pd r = a-b; return correct_deficit(r, 4*n); } // Input and output in [0, 4*n) template pd pd_LazyDoubleMod4(pd a, double n) { return 2 * pd_LazyReduce2(a, n); } // Input and output in [0, 2*n) template pd pd_LazyDoubleMod2(pd a, double n) { return 2 * pd_LazyReduce1(a, n); } // n in [0,2^50), b in [0,n), a in [0,4*n), bninv = RoundDown(b/n) // returns a*b mod n in [0, 2*n) template pd pd_LazyMulModPrecon(pd a, pd b, double n, pd bninv) { pd hi = a*b; pd lo = fused_mulsub(a, b, hi); // hi+lo == a*b (exactly) pd q = fused_muladd(a, bninv, 1L << 52); q -= (1L << 52); // q is the correct quotient, or one too small pd d = fused_negmuladd(q, n, hi); // d == hi - q*n (exactly) pd r = d + lo; // r is the remainder, or the remainder plus n return r; } // return (a[0] + a[1], a[0] - a[1], a[2] + a[3], a[2] - a[3], ...) // all inputs and outputs in [0, 2*n) template pd pd_fwd_butterfly_packed2(pd a, double n) { pd b = swap2(a); pd sum = pd_LazyAddMod(a, b, n); pd diff = pd_LazySubMod(b, a, n); pd res = blend2(sum, diff); res = pd_LazyReduce2(res, n); return res; } // return (a[0] + a[2], a[1] + a[3], (a[0] - a[2]), (a[1] - a[3])*root, ...) // all inputs and outputs in [0, 2*n) // it is also assumed that w = (1,1,1,root,...) and wninv = RoundDown(w/n) template pd pd_fwd_butterfly_packed4(pd a, pd w, double n, pd wninv) { pd b = swap4(a); pd sum = pd_LazyAddMod(a, b, n); pd diff = pd_LazySubMod(b, a, n); pd res = blend4(sum, diff); res = pd_LazyMulModPrecon(res, w, n, wninv); return res; } static double pd_LazyPrepMulModPrecon(long b, long n) { return double(b)/double(n); } //=================================== #define NTL_PD_FFT_THRESH (11) #define PDLGSZ NTL_LG2_PDSZ #define PDSZ NTL_PDSZ #if (PDSZ == 8) typedef PD<8> pd_full; typedef PD<4> pd_half; typedef PD<2> pd_qrtr; #else typedef PD<4> pd_full; typedef PD<2> pd_half; #endif #define PDLD pd_full::load // this assumes xx0, xx1, w, qinv are pd_half's #define fwd_butterfly_half(xx0, xx1, w, q, wqinv) \ do \ { \ pd_half x0_ = xx0; \ pd_half x1_ = xx1; \ pd_half t_ = pd_LazySubMod(x0_, x1_, q); \ xx0 = pd_LazyAddMod2(x0_, x1_, q); \ xx1 = pd_LazyMulModPrecon(t_, w, q, wqinv); \ } \ while (0) // this assumes xx0, xx1, w, qinv are pd_full's #define fwd_butterfly_full(xx0, xx1, w, q, wqinv) \ do \ { \ pd_full x0_ = xx0; \ pd_full x1_ = xx1; \ pd_full t_ = pd_LazySubMod(x0_, x1_, q); \ xx0 = pd_LazyAddMod2(x0_, x1_, q); \ xx1 = pd_LazyMulModPrecon(t_, w, q, wqinv); \ } \ while (0) // this assumes xx0_ptr, xx1_ptr, w_ptr, wqinv_ptr are double pointers // which are read/written as pd_full's. // In gcc, restrict keyword will help code gen. #define fwd_butterfly(xx0_ptr, xx1_ptr, w_ptr, q, wqinv_ptr) \ do \ { \ pd_full x0_ = PDLD(xx0_ptr); \ pd_full x1_ = PDLD(xx1_ptr); \ pd_full w_ = PDLD(w_ptr); \ pd_full wqinv_ = PDLD(wqinv_ptr); \ pd_full t_ = pd_LazySubMod(x0_, x1_, q); \ store(xx0_ptr, pd_LazyAddMod2(x0_, x1_, q)); \ store(xx1_ptr, pd_LazyMulModPrecon(t_, w_, q, wqinv_)); \ } \ while (0) #if 0 #define fwd_butterfly_x4(xx0_ptr, xx1_ptr, w_ptr, q, wqinv_ptr) \ do \ { \ pd_full xx0_0_ = PDLD(xx0_ptr+0*PDSZ); pd_full xx1_0_ = PDLD(xx1_ptr+0*PDSZ); \ pd_full xx0_1_ = PDLD(xx0_ptr+1*PDSZ); pd_full xx1_1_ = PDLD(xx1_ptr+1*PDSZ); \ pd_full xx0_2_ = PDLD(xx0_ptr+2*PDSZ); pd_full xx1_2_ = PDLD(xx1_ptr+2*PDSZ); \ pd_full xx0_3_ = PDLD(xx0_ptr+3*PDSZ); pd_full xx1_3_ = PDLD(xx1_ptr+3*PDSZ); \ fwd_butterfly_full(xx0_0_, xx1_0_, PDLD(w_ptr+0*PDSZ), q, PDLD(wqinv_ptr+0*PDSZ)); \ fwd_butterfly_full(xx0_1_, xx1_1_, PDLD(w_ptr+1*PDSZ), q, PDLD(wqinv_ptr+1*PDSZ)); \ fwd_butterfly_full(xx0_2_, xx1_2_, PDLD(w_ptr+2*PDSZ), q, PDLD(wqinv_ptr+2*PDSZ)); \ fwd_butterfly_full(xx0_3_, xx1_3_, PDLD(w_ptr+3*PDSZ), q, PDLD(wqinv_ptr+3*PDSZ)); \ store(xx0_ptr+0*PDSZ, xx0_0_); store(xx1_ptr+0*PDSZ, xx1_0_); \ store(xx0_ptr+1*PDSZ, xx0_1_); store(xx1_ptr+1*PDSZ, xx1_1_); \ store(xx0_ptr+2*PDSZ, xx0_2_); store(xx1_ptr+2*PDSZ, xx1_2_); \ store(xx0_ptr+3*PDSZ, xx0_3_); store(xx1_ptr+3*PDSZ, xx1_3_); \ } \ while(0) #else #define fwd_butterfly_x4(xx0_ptr, xx1_ptr, w_ptr, q, wqinv_ptr) \ do \ { \ fwd_butterfly(xx0_ptr+0*PDSZ, xx1_ptr+0*PDSZ, w_ptr+0*PDSZ, q, wqinv_ptr+0*PDSZ); \ fwd_butterfly(xx0_ptr+1*PDSZ, xx1_ptr+1*PDSZ, w_ptr+1*PDSZ, q, wqinv_ptr+1*PDSZ); \ fwd_butterfly(xx0_ptr+2*PDSZ, xx1_ptr+2*PDSZ, w_ptr+2*PDSZ, q, wqinv_ptr+2*PDSZ); \ fwd_butterfly(xx0_ptr+3*PDSZ, xx1_ptr+3*PDSZ, w_ptr+3*PDSZ, q, wqinv_ptr+3*PDSZ); \ } \ while(0) #endif static inline NTL_ALWAYS_INLINE void pd_fft_layer_inner_loop(double* NTL_RESTRICT xp0, double* NTL_RESTRICT xp1, long size, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { long j = 0; do { fwd_butterfly_x4(xp0+j, xp1+j, wtab+j, q, wqinvtab+j); j += 4*PDSZ; } while (j < size); } // assumes size >= 8*PDSZ static inline NTL_ALWAYS_INLINE void pd_fft_layer(double* xp, long blocks, long size, const double* wtab, const double* wqinvtab, double q) { size /= 2; do { pd_fft_layer_inner_loop(xp, xp+size, size, wtab, wqinvtab, q); xp += 2 * size; } while (--blocks != 0); } // size == 8*PDSZ static inline NTL_ALWAYS_INLINE void pd_fft_layer_size8(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { fwd_butterfly_x4(xp+0*PDSZ, xp+4*PDSZ, wtab, q, wqinvtab); xp += 8*PDSZ; } while (--blocks != 0); } // size == 4*PDSZ static inline NTL_ALWAYS_INLINE void pd_fft_layer_size4(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { fwd_butterfly(xp+0*PDSZ, xp+2*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); fwd_butterfly(xp+1*PDSZ, xp+3*PDSZ, wtab+1*PDSZ, q, wqinvtab+1*PDSZ); fwd_butterfly(xp+4*PDSZ, xp+6*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); fwd_butterfly(xp+5*PDSZ, xp+7*PDSZ, wtab+1*PDSZ, q, wqinvtab+1*PDSZ); xp += 8*PDSZ; blocks -= 2; } while (blocks != 0); } // size == 2*PDSZ static inline NTL_ALWAYS_INLINE void pd_fft_layer_size2(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { fwd_butterfly(xp+0*PDSZ, xp+1*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); fwd_butterfly(xp+2*PDSZ, xp+3*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); fwd_butterfly(xp+4*PDSZ, xp+5*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); fwd_butterfly(xp+6*PDSZ, xp+7*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); xp += 8*PDSZ; blocks -= 4; } while (blocks != 0); } #if (PDSZ == 8) static inline NTL_ALWAYS_INLINE void pd_fft_layer_size1_one_block(double* x, pd_half w8, pd_half w8qinv, pd_full w4, pd_full w4qinv, double q) { pd_half x0 = pd_half::load(x); pd_half x1 = pd_half::load(x+PDSZ/2); fwd_butterfly_half(x0, x1, w8, q, w8qinv); pd_full y = join(x0, x1); y = pd_fwd_butterfly_packed4(y, w4, q, w4qinv); y = pd_fwd_butterfly_packed2(y, q); store(x, y); } // size == PDSZ == 8 // processes last three levels, of size 8, 4, and 2. static inline NTL_ALWAYS_INLINE void pd_fft_layer_size1(double* xp, long blocks, const double **w_pp, const double **wqinv_pp, double q) { const double *w8_ptr = *w_pp; const double *w8qinv_ptr = *wqinv_pp; const double *w4_ptr = *(w_pp-1); const double *w4qinv_ptr = *(wqinv_pp-1); pd_half w8 = pd_half::load(w8_ptr); pd_half w8qinv = pd_half::load(w8qinv_ptr); pd_qrtr w4_qrtr = pd_qrtr::load(w4_ptr); pd_half w4_half = join(w4_qrtr, w4_qrtr); pd_full w4 = join(w4_half, w4_half); w4 = blend4(dup2even(w4), w4); pd_qrtr w4qinv_qrtr = pd_qrtr::load(w4qinv_ptr); pd_half w4qinv_half = join(w4qinv_qrtr, w4qinv_qrtr); pd_full w4qinv = join(w4qinv_half, w4qinv_half); w4qinv = blend4(dup2even(w4qinv), w4qinv); do { pd_fft_layer_size1_one_block(xp+0*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+1*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+2*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+3*PDSZ, w8, w8qinv, w4, w4qinv, q); xp += 4*PDSZ; blocks -= 4; } while (blocks != 0); } #else // PDSZ == 4 static inline NTL_ALWAYS_INLINE void pd_fft_layer_size1_one_block(double* x, pd_half w4, pd_half w4qinv, double q) { pd_half x0 = pd_half::load(x); pd_half x1 = pd_half::load(x+PDSZ/2); fwd_butterfly_half(x0, x1, w4, q, w4qinv); pd_full y = join(x0, x1); y = pd_fwd_butterfly_packed2(y, q); store(x, y); } // size == PDSZ == 4 // processes last two levels, of size 4 and 2. static inline NTL_ALWAYS_INLINE void pd_fft_layer_size1(double* xp, long blocks, const double **w_pp, const double **wqinv_pp, double q) { const double *w4_ptr = *w_pp; const double *w4qinv_ptr = *wqinv_pp; pd_half w4 = pd_half::load(w4_ptr); pd_half w4qinv = pd_half::load(w4qinv_ptr); do { pd_fft_layer_size1_one_block(xp+0*PDSZ, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+1*PDSZ, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+2*PDSZ, w4, w4qinv, q); pd_fft_layer_size1_one_block(xp+3*PDSZ, w4, w4qinv, q); xp += 4*PDSZ; blocks -= 4; } while (blocks != 0); } #endif void pd_fft_base(double* xp, long lgN, const pd_mod_t& mod) { double q = mod.q; const double** wtab = mod.wtab; const double** wqinvtab = mod.wqinvtab; long N = 1L << lgN; long j, size, blocks; for (j = lgN, size = N, blocks = 1; size > 8*PDSZ; j--, blocks <<= 1, size >>= 1) pd_fft_layer(xp, blocks, size, wtab[j], wqinvtab[j], q); pd_fft_layer_size8(xp, blocks, wtab[j], wqinvtab[j], q); j--, blocks <<= 1, size >>= 1; pd_fft_layer_size4(xp, blocks, wtab[j], wqinvtab[j], q); j--, blocks <<= 1, size >>= 1; pd_fft_layer_size2(xp, blocks, wtab[j], wqinvtab[j], q); j--, blocks <<= 1, size >>= 1; pd_fft_layer_size1(xp, blocks, wtab+j, wqinvtab+j, q); } static inline NTL_ALWAYS_INLINE void pd_move(double *x, const long *a) { pd_full r; loadu(r, a); store(x, r); } static inline NTL_ALWAYS_INLINE void pd_move(long *x, const double *a) { pd_full r; load(r, a); storeu(x, r); } static inline NTL_ALWAYS_INLINE void pd_reduce1_move(long *x, const double *a, double q) { pd_full r; load(r, a); r = pd_LazyReduce1(r, q); storeu(x, r); } static inline NTL_ALWAYS_INLINE void pd_reduce2_move(long *x, const double *a, double q) { pd_full r; load(r, a); r = pd_LazyReduce2(r, q); r = pd_LazyReduce1(r, q); storeu(x, r); } static inline NTL_ALWAYS_INLINE void pd_mul_move(long *x, const double *a, pd_full b, double q, pd_full bqinv) { pd_full r; load(r, a); r = pd_LazyMulModPrecon(r, b, q, bqinv); r = pd_LazyReduce1(r, q); storeu(x, r); } static void pd_fft_short(double* xp, long yn, long xn, long lgN, const pd_mod_t& mod) { long N = 1L << lgN; if (yn == N) { if (xn == N && lgN <= NTL_PD_FFT_THRESH) { // no truncation pd_fft_base(xp, lgN, mod); return; } } // divide-and-conquer algorithm long half = N >> 1; double q = mod.q; if (yn <= half) { if (xn <= half) { pd_fft_short(xp, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> X + Y for (long j = 0; j < xn; j+=PDSZ) store(xp+j, pd_LazyAddMod2(PDLD(xp+j), PDLD(xp+j+half), q)); pd_fft_short(xp, yn, half, lgN - 1, mod); } } else { yn -= half; double* xp0 = xp; double* xp1 = xp + half; const double* wtab = mod.wtab[lgN]; const double* wqinvtab = mod.wqinvtab[lgN]; if (xn <= half) { // X -> (X, w*X) for (long j = 0; j < xn; j+=PDSZ) store(xp1+j, pd_LazyMulModPrecon(PDLD(xp0+j), PDLD(wtab+j), q, PDLD(wqinvtab+j))); pd_fft_short(xp0, half, xn, lgN - 1, mod); pd_fft_short(xp1, yn, xn, lgN - 1, mod); } else { xn -= half; // (X, Y) -> (X + Y, w*(X - Y)) pd_fft_layer_inner_loop(xp0, xp1, xn, wtab, wqinvtab, q); // X -> (X, w*X) for (long j = xn; j < half; j+=PDSZ) store(xp1+j, pd_LazyMulModPrecon(PDLD(xp0+j), PDLD(wtab+j), q, PDLD(wqinvtab+j))); pd_fft_short(xp0, half, half, lgN - 1, mod); pd_fft_short(xp1, yn, half, lgN - 1, mod); } } } void pd_fft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, long xn) { for (long i = 0; i < xn; i += 4*PDSZ) { pd_move(xp+i+0*PDSZ, a+i+0*PDSZ); pd_move(xp+i+1*PDSZ, a+i+1*PDSZ); pd_move(xp+i+2*PDSZ, a+i+2*PDSZ); pd_move(xp+i+3*PDSZ, a+i+3*PDSZ); } pd_fft_short(xp, yn, xn, lgN, mod); double q = mod.q; for (long i = 0; i < yn; i += 4*PDSZ) { pd_reduce1_move(A+i+0*PDSZ, xp+i+0*PDSZ, q); pd_reduce1_move(A+i+1*PDSZ, xp+i+1*PDSZ, q); pd_reduce1_move(A+i+2*PDSZ, xp+i+2*PDSZ, q); pd_reduce1_move(A+i+3*PDSZ, xp+i+3*PDSZ, q); } } void pd_fft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, long xn, double fac) { for (long i = 0; i < xn; i += 4*PDSZ) { pd_move(xp+i+0*PDSZ, a+i+0*PDSZ); pd_move(xp+i+1*PDSZ, a+i+1*PDSZ); pd_move(xp+i+2*PDSZ, a+i+2*PDSZ); pd_move(xp+i+3*PDSZ, a+i+3*PDSZ); } pd_fft_short(xp, yn, xn, lgN, mod); double q = mod.q; double facqinv = fac/q; for (long i = 0; i < yn; i += 4*PDSZ) { pd_mul_move(A+i+0*PDSZ, xp+i+0*PDSZ, fac, q, facqinv); pd_mul_move(A+i+1*PDSZ, xp+i+1*PDSZ, fac, q, facqinv); pd_mul_move(A+i+2*PDSZ, xp+i+2*PDSZ, fac, q, facqinv); pd_mul_move(A+i+3*PDSZ, xp+i+3*PDSZ, fac, q, facqinv); } } //================ ifft ============== // return (a[0] + a[1], a[0] - a[1], a[2] + a[3], a[2] - a[3], ...) // all inputs and outputs in [0, 4*n) template pd pd_inv_butterfly_packed2(pd a, double n) { a = pd_LazyReduce2(a, n); pd b = swap2(a); pd sum = pd_LazyAddMod(a, b, n); pd diff = pd_LazySubMod(b, a, n); pd res = blend2(sum, diff); return res; } // return (a[0] + a[2], a[1] + a[3]*root, a[0] - a[2], a[1] - a[3]*root, ...) // all inputs and outputs in [0, 4*n) // it is also assumed that w = (1,1,1,root,...) and wninv = RoundDown(w/n) template pd pd_inv_butterfly_packed4(pd a, pd w, double n, pd wninv) { a = pd_LazyMulModPrecon(a, w, n, wninv); pd b = swap4(a); pd sum = pd_LazyAddMod(a, b, n); pd diff = pd_LazySubMod(b, a, n); pd res = blend4(sum, diff); return res; } #define inv_butterfly_half(xx0, xx1, w, q, wqinv) \ do \ { \ pd_half x0_ = pd_LazyReduce2(xx0, q); \ pd_half x1_ = xx1; \ pd_half t_ = pd_LazyMulModPrecon(x1_, w, q, wqinv); \ xx0 = pd_LazyAddMod(x0_, t_, q); \ xx1 = pd_LazySubMod(x0_, t_, q); \ } while (0) #define inv_butterfly(xx0_ptr, xx1_ptr, w_ptr, q, wqinv_ptr) \ do \ { \ pd_full x0_ = pd_LazyReduce2(PDLD(xx0_ptr), q); \ pd_full x1_ = PDLD(xx1_ptr); \ pd_full t_ = pd_LazyMulModPrecon(x1_, PDLD(w_ptr), q, PDLD(wqinv_ptr)); \ store(xx0_ptr, pd_LazyAddMod(x0_, t_, q)); \ store(xx1_ptr, pd_LazySubMod(x0_, t_, q)); \ } while (0) #define inv_butterfly_x4(xx0_ptr, xx1_ptr, w_ptr, q, wqinv_ptr) \ do \ { \ inv_butterfly(xx0_ptr+0*PDSZ, xx1_ptr+0*PDSZ, w_ptr+0*PDSZ, q, wqinv_ptr+0*PDSZ); \ inv_butterfly(xx0_ptr+1*PDSZ, xx1_ptr+1*PDSZ, w_ptr+1*PDSZ, q, wqinv_ptr+1*PDSZ); \ inv_butterfly(xx0_ptr+2*PDSZ, xx1_ptr+2*PDSZ, w_ptr+2*PDSZ, q, wqinv_ptr+2*PDSZ); \ inv_butterfly(xx0_ptr+3*PDSZ, xx1_ptr+3*PDSZ, w_ptr+3*PDSZ, q, wqinv_ptr+3*PDSZ); \ } \ while(0) static inline NTL_ALWAYS_INLINE void pd_ifft_layer_inner_loop(double* NTL_RESTRICT xp0, double* NTL_RESTRICT xp1, long size, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { long j = 0; do { inv_butterfly_x4(xp0+j, xp1+j, wtab+j, q, wqinvtab+j); j += 4*PDSZ; } while (j < size); } // assumes size >= 8*PDSZ static inline NTL_ALWAYS_INLINE void pd_ifft_layer(double* xp, long blocks, long size, const double* wtab, const double* wqinvtab, double q) { size /= 2; do { pd_ifft_layer_inner_loop(xp, xp+size, size, wtab, wqinvtab, q); xp += 2 * size; } while (--blocks != 0); } // size == 8*PDSZ static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size8(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { inv_butterfly_x4(xp+0*PDSZ, xp+4*PDSZ, wtab, q, wqinvtab); xp += 8*PDSZ; } while (--blocks != 0); } // size == 4*PDSZ static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size4(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { inv_butterfly(xp+0*PDSZ, xp+2*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); inv_butterfly(xp+1*PDSZ, xp+3*PDSZ, wtab+1*PDSZ, q, wqinvtab+1*PDSZ); inv_butterfly(xp+4*PDSZ, xp+6*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); inv_butterfly(xp+5*PDSZ, xp+7*PDSZ, wtab+1*PDSZ, q, wqinvtab+1*PDSZ); xp += 8*PDSZ; blocks -= 2; } while (blocks != 0); } // size == 2*PDSZ static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size2(double* NTL_RESTRICT xp, long blocks, const double* NTL_RESTRICT wtab, const double* NTL_RESTRICT wqinvtab, double q) { do { inv_butterfly(xp+0*PDSZ, xp+1*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); inv_butterfly(xp+2*PDSZ, xp+3*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); inv_butterfly(xp+4*PDSZ, xp+5*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); inv_butterfly(xp+6*PDSZ, xp+7*PDSZ, wtab+0*PDSZ, q, wqinvtab+0*PDSZ); xp += 8*PDSZ; blocks -= 4; } while (blocks != 0); } #if (PDSZ == 8) static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size1_one_block(double* x, pd_half w8, pd_half w8qinv, pd_full w4, pd_full w4qinv, double q) { pd_full y = PDLD(x); y = pd_inv_butterfly_packed2(y, q); y = pd_inv_butterfly_packed4(y, w4, q, w4qinv); pd_half x0 = get_lo(y); pd_half x1 = get_hi(y); inv_butterfly_half(x0, x1, w8, q, w8qinv); store(x, x0); store(x+PDSZ/2, x1); } // size == PDSZ == 8 // processes last three levels, of size 8, 4, and 2. static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size1(double* xp, long blocks, const double **w_pp, const double **wqinv_pp, double q) { const double *w8_ptr = *w_pp; const double *w8qinv_ptr = *wqinv_pp; const double *w4_ptr = *(w_pp-1); const double *w4qinv_ptr = *(wqinv_pp-1); pd_half w8 = pd_half::load(w8_ptr); pd_half w8qinv = pd_half::load(w8qinv_ptr); pd_qrtr w4_qrtr = pd_qrtr::load(w4_ptr); pd_half w4_half = join(w4_qrtr, w4_qrtr); pd_full w4 = join(w4_half, w4_half); w4 = blend4(dup2even(w4), w4); pd_qrtr w4qinv_qrtr = pd_qrtr::load(w4qinv_ptr); pd_half w4qinv_half = join(w4qinv_qrtr, w4qinv_qrtr); pd_full w4qinv = join(w4qinv_half, w4qinv_half); w4qinv = blend4(dup2even(w4qinv), w4qinv); do { pd_ifft_layer_size1_one_block(xp+0*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+1*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+2*PDSZ, w8, w8qinv, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+3*PDSZ, w8, w8qinv, w4, w4qinv, q); xp += 4*PDSZ; blocks -= 4; } while (blocks != 0); } #else // PDSZ == 4 static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size1_one_block(double* x, pd_half w4, pd_half w4qinv, double q) { pd_full y = PDLD(x); y = pd_inv_butterfly_packed2(y, q); pd_half x0 = get_lo(y); pd_half x1 = get_hi(y); inv_butterfly_half(x0, x1, w4, q, w4qinv); store(x, x0); store(x+PDSZ/2, x1); } // size == PDSZ == 4 // processes last two levels, of size 4 and 2. static inline NTL_ALWAYS_INLINE void pd_ifft_layer_size1(double* xp, long blocks, const double **w_pp, const double **wqinv_pp, double q) { const double *w4_ptr = *w_pp; const double *w4qinv_ptr = *wqinv_pp; pd_half w4 = pd_half::load(w4_ptr); pd_half w4qinv = pd_half::load(w4qinv_ptr); do { pd_ifft_layer_size1_one_block(xp+0*PDSZ, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+1*PDSZ, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+2*PDSZ, w4, w4qinv, q); pd_ifft_layer_size1_one_block(xp+3*PDSZ, w4, w4qinv, q); xp += 4*PDSZ; blocks -= 4; } while (blocks != 0); } #endif void pd_ifft_base(double* xp, long lgN, const pd_mod_t& mod) { double q = mod.q; const double** wtab = mod.wtab; const double** wqinvtab = mod.wqinvtab; long N = 1L << lgN; long j=PDLGSZ, size=PDSZ, blocks=N/PDSZ; pd_ifft_layer_size1(xp, blocks, wtab+j, wqinvtab+j, q); j++, blocks >>= 1, size <<= 1; pd_ifft_layer_size2(xp, blocks, wtab[j], wqinvtab[j], q); j++, blocks >>= 1, size <<= 1; pd_ifft_layer_size4(xp, blocks, wtab[j], wqinvtab[j], q); j++, blocks >>= 1, size <<= 1; pd_ifft_layer_size8(xp, blocks, wtab[j], wqinvtab[j], q); j++, blocks >>= 1, size <<= 1; for (; size <= N; j++, blocks >>= 1, size <<= 1) pd_ifft_layer(xp, blocks, size, wtab[j], wqinvtab[j], q); } static void pd_ifft_short2(double* xp, long yn, long lgN, const pd_mod_t& mod); static void pd_ifft_short1(double* xp, long yn, long lgN, const pd_mod_t& mod) // Implements truncated inverse FFT interface, but with xn==yn. // All computations are done in place. { long N = 1L << lgN; if (yn == N && lgN <= NTL_PD_FFT_THRESH) { // no truncation pd_ifft_base(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; double q = mod.q; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j+=PDSZ) store(xp+j, pd_LazyDoubleMod4(PDLD(xp+j), q)); pd_ifft_short1(xp, yn, lgN - 1, mod); } else { double* xp0 = xp; double* xp1 = xp + half; pd_ifft_short1(xp0, half, lgN - 1, mod); yn -= half; if (yn < half) { const double* wtab1 = mod.wtab1[lgN]; const double* wqinvtab1 = mod.wqinvtab1[lgN]; // X -> (2X, w*X) for (long j = yn; j < half; j+=PDSZ) { pd_full x0 = PDLD(xp0+j); store(xp0+j, pd_LazyDoubleMod4(x0, q)); store(xp1+j, pd_LazyMulModPrecon(x0, PDLD(wtab1+j), q, PDLD(wqinvtab1+j))); } } pd_ifft_short2(xp1, yn, lgN - 1, mod); // (X, Y) -> (X + Y/w, X - Y/w) pd_ifft_layer_inner_loop(xp0, xp1, yn, mod.wtab[lgN], mod.wqinvtab[lgN], q); } } static void pd_ifft_short2(double* xp, long yn, long lgN, const pd_mod_t& mod) // Implements truncated inverse FFT interface, but with xn==N. // All computations are done in place. { long N = 1L << lgN; if (yn == N && lgN <= NTL_PD_FFT_THRESH) { // no truncation pd_ifft_base(xp, lgN, mod); return; } // divide-and-conquer algorithm long half = N >> 1; double q = mod.q; if (yn <= half) { // X -> 2X for (long j = 0; j < yn; j+=PDSZ) store(xp+j, pd_LazyDoubleMod4(PDLD(xp+j), q)); // (X, Y) -> X + Y for (long j = yn; j < half; j+=PDSZ) store(xp+j, pd_LazyAddMod4(PDLD(xp+j), PDLD(xp+j+half), q)); pd_ifft_short2(xp, yn, lgN - 1, mod); // (X, Y) -> X - Y for (long j = 0; j < yn; j+=PDSZ) store(xp+j, pd_LazySubMod4(PDLD(xp+j), PDLD(xp+j+half), q)); } else { double* xp0 = xp; double* xp1 = xp + half; pd_ifft_short1(xp0, half, lgN - 1, mod); yn -= half; if (yn < half) { const double* wtab1 = mod.wtab1[lgN]; const double* wqinvtab1 = mod.wqinvtab1[lgN]; // (X, Y) -> (2X - Y, w*(X - Y)) for (long j = yn; j < half; j+=PDSZ) { pd_full x0 = PDLD(xp0+j); pd_full x1 = PDLD(xp1+j); pd_full u = pd_LazySubMod4(x0, x1, q); store(xp0+j, pd_LazyAddMod4(x0, u, q)); store(xp1+j, pd_LazyMulModPrecon(u, PDLD(wtab1+j), q, PDLD(wqinvtab1+j))); } } pd_ifft_short2(xp1, yn, lgN - 1, mod); // (X, Y) -> (X + Y/w, X - Y/w) pd_ifft_layer_inner_loop(xp0, xp1, yn, mod.wtab[lgN], mod.wqinvtab[lgN], q); } } void pd_ifft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, double fac) { long N = 1L << lgN; for (long i = 0; i < yn; i += 4*PDSZ) { pd_move(xp+i+0*PDSZ, a+i+0*PDSZ); pd_move(xp+i+1*PDSZ, a+i+1*PDSZ); pd_move(xp+i+2*PDSZ, a+i+2*PDSZ); pd_move(xp+i+3*PDSZ, a+i+3*PDSZ); } pd_ifft_short1(xp, yn, lgN, mod); double q = mod.q; double facqinv = fac/q; for (long i = 0; i < yn; i += 4*PDSZ) { pd_mul_move(A+i+0*PDSZ, xp+i+0*PDSZ, fac, q, facqinv); pd_mul_move(A+i+1*PDSZ, xp+i+1*PDSZ, fac, q, facqinv); pd_mul_move(A+i+2*PDSZ, xp+i+2*PDSZ, fac, q, facqinv); pd_mul_move(A+i+3*PDSZ, xp+i+3*PDSZ, fac, q, facqinv); } } void pd_ifft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn) { long N = 1L << lgN; for (long i = 0; i < yn; i += 4*PDSZ) { pd_move(xp+i+0*PDSZ, a+i+0*PDSZ); pd_move(xp+i+1*PDSZ, a+i+1*PDSZ); pd_move(xp+i+2*PDSZ, a+i+2*PDSZ); pd_move(xp+i+3*PDSZ, a+i+3*PDSZ); } pd_ifft_short1(xp, yn, lgN, mod); double q = mod.q; for (long i = 0; i < yn; i += 4*PDSZ) { pd_reduce2_move(A+i+0*PDSZ, xp+i+0*PDSZ, q); pd_reduce2_move(A+i+1*PDSZ, xp+i+1*PDSZ, q); pd_reduce2_move(A+i+2*PDSZ, xp+i+2*PDSZ, q); pd_reduce2_move(A+i+3*PDSZ, xp+i+3*PDSZ, q); } } NTL_END_IMPL #else void _ntl_pd_FFT_dummy() { } #endif ntl-11.5.1/src/MakeGetTime0000644417616742025610000000355314064716022017031 0ustar gid-shoupvpug-gid-shoupv if test -f GetTime.cpp then rm GetTime.cpp fi echo "does anybody really know what time it is?" sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.cpp GetTime1.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetTime TestGetTime.cpp GetTime1.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 >> "CheckFeatures.log" 2>&1 then cp GetTime1.cpp GetTime.cpp echo "using GetTime1.cpp" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.cpp GetTime2.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetTime TestGetTime.cpp GetTime2.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 >> "CheckFeatures.log" 2>&1 then cp GetTime2.cpp GetTime.cpp echo "using GetTime2.cpp" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.cpp GetTime3.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetTime TestGetTime.cpp GetTime3.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 >> "CheckFeatures.log" 2>&1 then cp GetTime3.cpp GetTime.cpp echo "using GetTime3.cpp" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.cpp GetTime4.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetTime TestGetTime.cpp GetTime4.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetTime then if ./TestGetTime 1 1048576 1048575 >> "CheckFeatures.log" 2>&1 then cp GetTime4.cpp GetTime.cpp echo "using GetTime4.cpp" exit 0 fi fi sh RemoveProg TestGetTime echo $1 -o TestGetTime TestGetTime.cpp GetTime5.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetTime TestGetTime.cpp GetTime5.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetTime then cp GetTime5.cpp GetTime.cpp echo "using GetTime5.cpp" echo "warning: this GetTime function always returns 0" exit 0 else echo "something is wrong..." exit 1 fi ntl-11.5.1/src/MakeGetPID0000644417616742025610000000070614064716022016544 0ustar gid-shoupvpug-gid-shoupv if test -f GetPID.cpp then rm GetPID.cpp fi echo "who am I?" sh RemoveProg TestGetPID echo $1 -o TestGetPID TestGetPID.cpp GetPID1.cpp $2 >> "CheckFeatures.log" 2>&1 $1 -o TestGetPID TestGetPID.cpp GetPID1.cpp $2 >> "CheckFeatures.log" 2>&1 if test -f TestGetPID then cp GetPID1.cpp GetPID.cpp echo "using GetPID1.cpp" exit 0 fi cp GetPID2.cpp GetPID.cpp echo "using GetPID2.cpp" echo "warning: this GetPID function always returns 0" exit 0 ntl-11.5.1/src/MakeCheckFeatures0000644417616742025610000000132214064716022020177 0ustar gid-shoupvpug-gid-shoupv # invoked as: sh MakeCheckFeatures "$(FEATURES)" "$(LINK)" "$(LDLIBS)" for f in $1 do printf '*** Checking for feature: %s ' "$f" echo "" > "../include/NTL/HAVE_$f.h" sh RemoveProg CheckFeatures echo $2 Check$f.cpp -o CheckFeatures $3 >> "CheckFeatures.log" 2>&1 $2 Check$f.cpp -o CheckFeatures $3 >> "CheckFeatures.log" 2>&1 if test -f CheckFeatures then if ./CheckFeatures then echo "[yes]" echo "#ifndef NTL_HAVE_$f" > "../include/NTL/HAVE_$f.h" echo "#define NTL_HAVE_$f" >> "../include/NTL/HAVE_$f.h" echo "#endif" >> "../include/NTL/HAVE_$f.h" sh RemoveProg CheckFeatures else echo "[no]" fi else echo "[no]" fi done exit 0 ntl-11.5.1/src/ResetFeatures0000644417616742025610000000124714064716022017454 0ustar gid-shoupvpug-gid-shoupv echo "" > "$1/include/NTL/ALL_FEATURES.h" echo "" > "$1/include/NTL/REPORT_ALL_FEATURES.h" rm -f "$1"/include/NTL/HAVE_*.h for f in $2 do echo "" > "$1/include/NTL/HAVE_$f.h" echo "#include " >> "$1/include/NTL/ALL_FEATURES.h" echo "#ifdef NTL_HAVE_$f" >> "$1/include/NTL/REPORT_ALL_FEATURES.h" # need to use printf for this -- echo is not portable enough # to handle the backslash-n printf " std::cerr << \"NTL_HAVE_$f\\\\n\";\n" >> "$1/include/NTL/REPORT_ALL_FEATURES.h" echo "#endif" >> "$1/include/NTL/REPORT_ALL_FEATURES.h" echo "" >> "$1/include/NTL/REPORT_ALL_FEATURES.h" done echo "" >> "$1/include/NTL/ALL_FEATURES.h" ntl-11.5.1/src/CopyFeatures0000644417616742025610000000017614064716022017304 0ustar gid-shoupvpug-gid-shoupv for f in $3 do cp "$1/include/NTL/HAVE_$f.h" "$2/include/NTL/" done cp "$1/include/NTL/ALL_FEATURES.h" "$2/include/NTL/" ntl-11.5.1/src/TestScript0000644417616742025610000001131214064716022016771 0ustar gid-shoupvpug-gid-shoupvMAKE_PROG="$1" echo echo "---------------------------------" echo "making ZZTest" $MAKE_PROG ZZTest echo "running ZZTest" ./ZZTest sh RemoveProg ZZTest echo echo "---------------------------------" echo "making SSMulTest" $MAKE_PROG SSMulTest echo "running SSMulTest" ./SSMulTest sh RemoveProg SSMulTest echo echo "---------------------------------" echo "making ZZ_pXTest" $MAKE_PROG ZZ_pXTest echo "running ZZ_pXTest" ./ZZ_pXTest sh RemoveProg ZZ_pXTest echo echo "---------------------------------" echo "making lzz_pXTest" $MAKE_PROG lzz_pXTest echo "running lzz_pXTest" ./lzz_pXTest sh RemoveProg lzz_pXTest echo echo "---------------------------------" echo "making CanZassTest" $MAKE_PROG CanZassTest echo "running CanZassTest" ./CanZassTest < CanZassTestIn > XXX sh RemoveProg CanZassTest if diff -b XXX CanZassTestOut then echo "CanZassTest OK" else echo "bad CanZassTest" fi echo echo "---------------------------------" echo "making BerlekampTest" $MAKE_PROG BerlekampTest echo "running BerlekampTest" ./BerlekampTest < BerlekampTestIn > XXX sh RemoveProg BerlekampTest if diff -b XXX BerlekampTestOut then echo "BerlekampTest OK" else echo "bad BerlekampTest" fi echo echo "---------------------------------" echo "making ZZXFacTest" $MAKE_PROG ZZXFacTest echo "running ZZXFacTest" ./ZZXFacTest < ZZXFacTestIn > XXX sh RemoveProg ZZXFacTest if diff -b XXX ZZXFacTestOut then echo "ZZXFacTest OK" else echo "bad ZZXFacTest" fi echo echo "---------------------------------" echo "making MoreFacTest" $MAKE_PROG MoreFacTest echo "running MoreFacTest" ./MoreFacTest < MoreFacTestIn sh RemoveProg MoreFacTest echo echo "---------------------------------" echo "making GF2XTest" $MAKE_PROG GF2XTest echo "running GF2XTest" ./GF2XTest sh RemoveProg GF2XTest echo echo "---------------------------------" echo "making GF2EXTest" $MAKE_PROG GF2EXTest echo "running GF2EXTest" ./GF2EXTest sh RemoveProg GF2EXTest echo echo "---------------------------------" echo "making GF2EXGCDTest" $MAKE_PROG GF2EXGCDTest echo "running GF2EXGCDTest" ./GF2EXGCDTest sh RemoveProg GF2EXGCDTest echo echo "---------------------------------" echo "making MatrixTest" $MAKE_PROG MatrixTest echo "running MatrixTest" ./MatrixTest < MatrixTestIn > XXX sh RemoveProg MatrixTest if diff -b XXX MatrixTestOut then echo "MatrixTest OK" else echo "bad MatrixTest" fi echo echo "---------------------------------" echo "making mat_lzz_pTest" $MAKE_PROG mat_lzz_pTest echo "running mat_lzz_pTest" ./mat_lzz_pTest sh RemoveProg mat_lzz_pTest echo echo "---------------------------------" echo "making CharPolyTest" $MAKE_PROG CharPolyTest echo "running CharPolyTest" ./CharPolyTest < CharPolyTestIn > XXX sh RemoveProg CharPolyTest if diff -b XXX CharPolyTestOut then echo "CharPolyTest OK" else echo "bad CharPolyTest" fi echo echo "---------------------------------" echo "making BitMatTest" $MAKE_PROG BitMatTest echo "running BitMatTest" ./BitMatTest sh RemoveProg BitMatTest echo echo "---------------------------------" echo "making RRTest" $MAKE_PROG RRTest echo "running RRTest" ./RRTest < RRTestIn > XXX sh RemoveProg RRTest if diff -b XXX RRTestOut then echo "RRTest OK" else echo "bad RRTest" fi echo echo "---------------------------------" echo "making QuadTest" $MAKE_PROG QuadTest echo "running QuadTest" ./QuadTest < QuadTestIn > XXX sh RemoveProg QuadTest if diff -b XXX QuadTestOut then echo "QuadTest OK" else echo "bad QuadTest" fi echo echo "---------------------------------" echo "making LLLTest" $MAKE_PROG LLLTest echo "running LLLTest" ./LLLTest < LLLTestIn > XXX sh RemoveProg LLLTest if diff -b XXX LLLTestOut then echo "LLLTest OK" else echo "bad LLLTest" fi echo echo "---------------------------------" echo "making subset" $MAKE_PROG subset echo "subset 40 40 20 10 999999 f" ./subset <> dos/include/NTL/PackageInfo.h for i in $3 do cp ../doc/$i dos/doc/$i done for i in $4 do cp $i dos/tests/$i done cp $5 dos/tests cp cfileout dos/include/NTL/config.h sh ResetFeatures dos "$6" ntl-11.5.1/src/unixify0000644417616742025610000000073314064716022016365 0ustar gid-shoupvpug-gid-shoupv rm -rf unix mkdir unix mkdir unix/src mkdir unix/include mkdir unix/include/NTL mkdir unix/doc cp ../README unix/README for i in $1 do cp $i unix/src/ done for i in $2 do cp ../include/NTL/$i unix/include/NTL/ done echo "#define NTL_PACKAGE (1)" >> unix/include/NTL/PackageInfo.h for i in $3 do cp ../doc/$i unix/doc/ done sh ResetFeatures unix "$4" for f in $4 do cp Check$f.cpp unix/src/ done cp -R libtool-seed unix/src cp -R libtool-origin unix/src ntl-11.5.1/src/RemoveProg0000644417616742025610000000020014064716022016744 0ustar gid-shoupvpug-gid-shoupv for i in $* do rm -f "$i" rm -f "$i.exe" rm -f ".libs/$i" rm -f ".libs/$i.exe" rm -rf "$i.dSYM" done exit 0 ntl-11.5.1/src/configure0000755417616742025610000000055014064716022016653 0ustar gid-shoupvpug-gid-shoupv#!/bin/sh # This is just a shell script that calls perl. # Since perl may be located in a wierd place, this # should be more portable than using a direct "shebang". # Also, some shells do not handle "$@" correctly when # no options are supplied, so this is handled as a special case. if test $# -ne 0 then perl DoConfig "$@" else perl DoConfig fi ntl-11.5.1/src/DoConfig0000644417616742025610000004650114064716022016365 0ustar gid-shoupvpug-gid-shoupv# This is a perl script, invoked from a shell use warnings; # this doesn't work on older versions of perl system("echo '*** CompilerOutput.log ***' > CompilerOutput.log"); %MakeFlag = ( 'SHARED' => 'off', 'NATIVE' => 'on', ); %MakeVal = ( 'CXX' => 'g++', 'CXXFLAGS' => '-g -O2', 'CXXAUTOFLAGS'=> '', 'NOCONTRACT' => '', 'AR' => 'ar', 'ARFLAGS' => 'ruv', 'RANLIB' => 'ranlib', 'LIBTOOL' => undef, 'LIBTOOL_LINK_FLAGS' => '', 'LIBTOOL_LINK_LIBS' => undef, 'LDFLAGS' => '', 'LDLIBS' => '-lm', 'CPPFLAGS' => '', 'DEF_PREFIX' => '/usr/local', 'PREFIX' => '$(DEF_PREFIX)', 'LIBDIR' => '$(PREFIX)/lib', 'INCLUDEDIR' => '$(PREFIX)/include', 'DOCDIR' => '$(PREFIX)/share/doc', 'GMP_PREFIX' => '$(DEF_PREFIX)', 'GMP_INCDIR' => '$(GMP_PREFIX)/include', 'GMP_LIBDIR' => '$(GMP_PREFIX)/lib', 'GF2X_PREFIX' => '$(DEF_PREFIX)', 'GF2X_INCDIR' => '$(GF2X_PREFIX)/include', 'GF2X_LIBDIR' => '$(GF2X_PREFIX)/lib', 'MAKE_PROG' => 'make', 'TUNE' => 'generic', ); %ConfigFlag = ( 'NTL_LEGACY_NO_NAMESPACE' => 'off', 'NTL_LEGACY_INPUT_ERROR' => 'off', 'NTL_DISABLE_LONGDOUBLE' => 'off', 'NTL_DISABLE_LONGLONG' => 'off', 'NTL_DISABLE_LL_ASM' => 'off', 'NTL_MAXIMIZE_SP_NBITS' => 'off', 'NTL_LEGACY_SP_MULMOD' => 'off', 'NTL_THREADS' => 'on', 'NTL_TLS_HACK' => 'on', 'NTL_EXCEPTIONS' => 'off', 'NTL_STD_CXX11' => 'on', 'NTL_STD_CXX14' => 'off', 'NTL_DISABLE_MOVE_ASSIGN' => 'on', 'NTL_DISABLE_MOVE' => 'off', 'NTL_THREAD_BOOST' => 'on', 'NTL_GMP_LIP' => 'on', 'NTL_GF2X_LIB' => 'off', 'NTL_X86_FIX' => 'off', 'NTL_NO_X86_FIX' => 'off', 'NTL_NO_INIT_TRANS' => 'on', 'NTL_CLEAN_INT' => 'off', 'NTL_CLEAN_PTR' => 'on', 'NTL_SAFE_VECTORS' => 'on', 'NTL_RANGE_CHECK' => 'off', 'NTL_ENABLE_AVX_FFT' => 'off', 'NTL_AVOID_AVX512' => 'off', 'NTL_SPMM_ULL' => 'off', 'NTL_AVOID_BRANCHING' => 'off', 'NTL_FFT_BIGTAB' => 'off', 'NTL_FFT_LAZYMUL' => 'off', 'NTL_TBL_REM' => 'off', 'NTL_CRT_ALTCODE' => 'off', 'NTL_CRT_ALTCODE_SMALL' => 'off', 'NTL_GF2X_NOINLINE' => 'off', 'NTL_GF2X_ALTCODE' => 'off', 'NTL_GF2X_ALTCODE1' => 'off', 'NTL_RANDOM_AES256CTR' => 'off', ); %ConfigVal = ( 'NTL_UNSIGNED_LONG_LONG_TYPE' => undef, ); %Variable = (); $nowrite = 0; foreach $arg (@ARGV) { if ($arg =~ '^(-h|help|-help|--help)$') { system("more ../doc/config.txt"); exit 0; } if ($arg =~ '^--nowrite$') { $nowrite = 1; next; } if (($name, $val) = ($arg =~ /(.*?)=(.*)/)) { $Variable{$name} = 0; if (exists($MakeFlag{$name}) && ($val =~ 'on|off')) { $MakeFlag{$name} = $val; next; } elsif (exists($MakeVal{$name})) { $MakeVal{$name} = $val; next; } elsif (exists($ConfigFlag{$name}) && ($val =~ 'on|off')) { $ConfigFlag{$name} = $val; next; } elsif (exists($ConfigVal{$name})) { $ConfigVal{$name} = $val; next; } } die "Error: unrecognized option: $arg\ntype \"./configure -h\" for help\n"; } # warn against -O3, -Ofast, -ffast-math if ($MakeVal{'CXXFLAGS'} =~ '-O3') { Warning("-O3 flag may yield incorrect code"); } if ($MakeVal{'CXXFLAGS'} =~ '-Ofast') { Warning("-Ofast flag may yield incorrect code"); } if ($MakeVal{'CXXFLAGS'} =~ '-ffast-math') { Warning("-ffast-math flag may yield incorrect code"); } # special processing: NTL_THREADS=off => NTL_THREAD_BOOST=off if ($ConfigFlag{'NTL_THREADS'} eq 'off') { $ConfigFlag{'NTL_THREAD_BOOST'} = 'off'; } # special processing: CXXFLAGS contains '-march=' => NATIVE=off if ($MakeVal{'CXXFLAGS'} =~ '-march=') { $MakeFlag{'NATIVE'} = 'off'; } # some special MakeVal values that are determined by SHARED if ($MakeFlag{'SHARED'} eq 'off') { $MakeVal{'LSTAT'} = ''; $MakeVal{'LSHAR'} = '# '; if (!defined($MakeVal{'LIBTOOL'})) { $MakeVal{'LIBTOOL'} = 'libtool'; } if (!defined($MakeVal{'LIBTOOL_LINK_LIBS'})) { $MakeVal{'LIBTOOL_LINK_LIBS'} = ''; } } else { $MakeVal{'LSTAT'} = '# '; $MakeVal{'LSHAR'} = ''; if (!defined($MakeVal{'LIBTOOL'})) { # build libtool $MakeVal{'LIBTOOL'} = './libtool-build/libtool'; print "\n\n*** building libtool\n\n"; system("rm -rf libtool-build") and die "Error: libtool build failed\n"; system("cp -R libtool-origin libtool-build") and die "Error: libtool build failed\n"; system("cd libtool-build && ./configure") and die "Error: libtool build failed\n"; if (-x "libtool-build/libtool") { print "\n*** libtool OK\n\n"; } else { die "Error: libtool not created\n"; } } else { # sanity check for existing libtool print("***** checking for libtool *****\n"); if (system("$MakeVal{'LIBTOOL'} --version")) { die "Error: bad libtool ($MakeVal{'LIBTOOL'}) -- try glibtool?"; } print("***** libtool OK *****\n\n"); } # special processing to make sure -lpthread gets passed # to libtool, to prevent so-called "underlinking". # This helps to ensure that clients using NTL as a shared library # do not need to pass -pthread when compiling. if (!defined($MakeVal{'LIBTOOL_LINK_LIBS'})) { if ($ConfigFlag{'NTL_THREADS'} eq 'on') { $MakeVal{'LIBTOOL_LINK_LIBS'} = '-lpthread'; } } } # special GMP variables $MakeVal{'GMPI'} = '# '; $MakeVal{'GMPL'} = '# '; $MakeVal{'GMP'} = '# '; if ($ConfigFlag{'NTL_GMP_LIP'} eq 'on') { $MakeVal{'GMP'} = ''; if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GMP_PREFIX'}) || exists($Variable{'GMP_INCDIR'})) { $MakeVal{'GMPI'} = ''; } if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GMP_PREFIX'}) || exists($Variable{'GMP_LIBDIR'})) { $MakeVal{'GMPL'} = ''; } } # special GF2X variables $MakeVal{'GF2XI'} = '# '; $MakeVal{'GF2XL'} = '# '; $MakeVal{'GF2X'} = '# '; if ($ConfigFlag{'NTL_GF2X_LIB'} eq 'on') { $MakeVal{'GF2X'} = ''; if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GF2X_PREFIX'}) || exists($Variable{'GF2X_INCDIR'})) { $MakeVal{'GF2XI'} = ''; } if (exists($Variable{'DEF_PREFIX'}) || exists($Variable{'GF2X_PREFIX'}) || exists($Variable{'GF2X_LIBDIR'})) { $MakeVal{'GF2XL'} = ''; } } # copy %MakeVal and %MakeFlag as is into %MakeSub %MakeSub = (%MakeVal, %MakeFlag); # copy %ConfigFlag into %ConfigSub, substituting 0 for off and 1 of on %ConfigSub = ( ); foreach $name (keys %ConfigFlag) { if ($ConfigFlag{$name} eq 'on') { $ConfigSub{$name} = 1; } else { $ConfigSub{$name} = 0; } } # special logic for NTL_UNSIGNED_LONG_LONG_TYPE if (defined($ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'})) { $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = $ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'}; $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 1; } else { $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = 'unsigned long long'; $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 0; } # special logic for WIZARD_HACK $ConfigSub{'WIZARD_HACK'} = ''; # some extra logic consistency checks if ($ConfigSub{'NTL_X86_FIX'} + $ConfigSub{'NTL_NO_X86_FIX'} > 1) { die "Error: at most one of NTL_X86_FIX and NTL_NO_X86_FIX may be on\n"; } if ($ConfigSub{'NTL_GF2X_ALTCODE'} + $ConfigSub{'NTL_GF2X_ALTCODE1'} > 1) { die "Error: at most one of NTL_GF2X_ALTCODE and NTL_GF2X_ALTCODE1 may be on\n"; } if ($ConfigSub{'NTL_CRT_ALTCODE'} + $ConfigSub{'NTL_CRT_ALTCODE_SMALL'} > 1) { die "Error: at most one of NTL_CRT_ALTCODE and NTL_CRT_ALTCODE_SMALL may be on\n"; } if ($ConfigSub{'NTL_ENABLE_AVX_FFT'} == 1 && $MakeSub{'TUNE'} eq 'auto') { die "Error: incompatible options NTL_ENABLE_AVX_FFT=on and TUNE=auto\n"; } # # # useful auxilliary routines sub Warning { my ($s) = @_; printf("\n*** WARNING: \n%s\n\n", $s); return 1; } sub RemoveProg { # This should work on unix and cygwin on windows my ($name) = @_; unlink($name); unlink("$name.exe"); return 1; } sub RemoveFile { my ($name) = @_; unlink($name); return 1; } sub GenFiles { open(MFILE, "< mfile"); open(MFILEOUT, "> mfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$MakeSub{$1}/ge; print MFILEOUT $line; } close(MFILE); close(MFILEOUT); # generate config.h open(CFILE, "< cfile"); open(CFILEOUT, "> cfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$ConfigSub{$1}/ge; print CFILEOUT $line; } close(CFILE); close(CFILEOUT); open(HFILEOUT, "> hfileout"); $argstr = join(' ', @ARGV); print HFILEOUT "#if 0\n"; print HFILEOUT "generated by ./configure $argstr\n\n"; my @flag = ("off", "on"); foreach $name (sort keys %ConfigSub) { if ($name eq 'NTL_UNSIGNED_LONG_LONG_TYPE') { print HFILEOUT "$name=\"$ConfigSub{$name}\"\n"; } elsif ($name eq 'FLAG_UNSIGNED_LONG_LONG_TYPE' || $name eq 'WIZARD_HACK') { # do nothing } else { #print HFILEOUT "*** $ConfigSub{$name}\n"; print HFILEOUT "$name=" . $flag[$ConfigSub{$name}] . "\n"; } } print HFILEOUT "\n"; foreach $name (sort keys %MakeSub) { print HFILEOUT "$name=\"$MakeSub{$name}\"\n"; } #print HFILEOUT "CXXFLAGS=\"$MakeSub{'CXXFLAGS'}\"\n"; #print HFILEOUT "CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n"; #print HFILEOUT "NOCONTRACT=\"$MakeSub{'NOCONTRACT'}\"\n"; print HFILEOUT "#endif\n"; close(HFILEOUT); return 1; } sub CopyFiles { system("cp mfileout makefile") and die "Error: CopyFile failed"; system("cp cfileout ../include/NTL/config.h") and die "Error: CopyFile failed";; system("cp hfileout ../include/NTL/ConfigLog.h") and die "Error: CopyFile failed"; return 1; } sub Exec { my ($name) = @_; GenFiles(); CopyFiles(); RemoveProg("$name"); system("$MakeVal{'MAKE_PROG'} $name > OneCompilerOutput.log 2>&1") and RemoveProg("$name") and return 0; system("cat OneCompilerOutput.log >> CompilerOutput.log"); my $output = `cat OneCompilerOutput.log`; if ($output =~ /^icc: command line warning/m) { # icc just gives warnings for bad command line args RemoveProg("$name") and return 0; } system("./$name") and RemoveProg("$name") and return 0; RemoveProg("$name") and return 1; } sub CheckCompile { return Exec("CheckCompile"); } sub CheckFlag { my ($flag) = @_; my $try_flags = $MakeSub{'CXXAUTOFLAGS'}; print "*** checking $flag flag\n"; system("echo '*** checking $flag flag' >> CompilerOutput.log"); $MakeSub{'CXXAUTOFLAGS'} = $MakeSub{'CXXAUTOFLAGS'} . ' ' . $flag; print(" CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n"); if (CheckCompile()) { print " $flag works\n"; return 1; } else { $MakeSub{'CXXAUTOFLAGS'} = $try_flags; print " $flag does not work\n"; return 0; } } $min_std = 0; $pthread_flag = 0; $native_flag = 0; # special processing for NTL_THREADS if ($ConfigSub{'NTL_THREADS'}) { $min_std = 2011; # ' -std=c++11'; $pthread_flag = 1; # ' -pthread'; } # special processing for NTL_EXCEPTIONS if ($ConfigSub{'NTL_EXCEPTIONS'}) { $min_std=2011; # ' -std=c++11'; } # special processing for NTL_SAFE_VECTORS if ($ConfigSub{'NTL_SAFE_VECTORS'}) { $min_std=2011; # ' -std=c++11'; } # special processing for NATIVE if ($MakeFlag{'NATIVE'} eq 'on') { $native_flag = 1; # ' -march=native'; } if ($ConfigSub{'NTL_STD_CXX14'}) { $min_std = 2014; } elsif ($ConfigSub{'NTL_STD_CXX11'}) { $min_std = 2011; } elsif ($min_std) { $ConfigSub{'NTL_STD_CXX11'} = 1; } sub Process_TUNE { # special processing for TUNE --- WIZARD gets set here as well if ($MakeSub{'TUNE'} eq 'auto') { $MakeSub{'WIZARD'} = 'on'; } else { $MakeSub{'WIZARD'} = 'off'; if ($MakeSub{'TUNE'} eq 'generic') { # the default values are set to ensure reasonably good performance # across a wide range of architectures, but it's better to run the # Wizard. Here, I don't want to assume a cmov-like instruction, # so we set AVOID_BRANCHING to be on the safe side. $ConfigSub{'NTL_SPMM_ULL'} = 1, $ConfigSub{'NTL_AVOID_BRANCHING'} = 1, $ConfigSub{'NTL_FFT_BIGTAB'} = 1, $ConfigSub{'NTL_FFT_LAZYMUL'} = 1, $ConfigSub{'NTL_TBL_REM'} = 1, $ConfigSub{'NTL_CRT_ALTCODE'} = 1, $ConfigSub{'NTL_CRT_ALTCODE_SMALL'} = 0, $ConfigSub{'NTL_GF2X_NOINLINE'} = 0, $ConfigSub{'NTL_GF2X_ALTCODE'} = 0, $ConfigSub{'NTL_GF2X_ALTCODE1'} = 1, } elsif ($MakeSub{'TUNE'} eq 'x86') { # these settings should work pretty well across x86's # the most important assumption is that we have the cmov # instruction $ConfigSub{'NTL_SPMM_ULL'} = 1, $ConfigSub{'NTL_AVOID_BRANCHING'} = 0, $ConfigSub{'NTL_FFT_BIGTAB'} = 1, $ConfigSub{'NTL_FFT_LAZYMUL'} = 1, $ConfigSub{'NTL_TBL_REM'} = 1, $ConfigSub{'NTL_CRT_ALTCODE'} = 1, $ConfigSub{'NTL_CRT_ALTCODE_SMALL'} = 0, $ConfigSub{'NTL_GF2X_NOINLINE'} = 0, $ConfigSub{'NTL_GF2X_ALTCODE'} = 0, $ConfigSub{'NTL_GF2X_ALTCODE1'} = 1, } elsif ($MakeSub{'TUNE'} eq 'linux-s390x') { $ConfigSub{'NTL_SPMM_ULL'} = 0, $ConfigSub{'NTL_AVOID_BRANCHING'} = 1, $ConfigSub{'NTL_FFT_BIGTAB'} = 1, $ConfigSub{'NTL_FFT_LAZYMUL'} = 1, $ConfigSub{'NTL_TBL_REM'} = 1, $ConfigSub{'NTL_CRT_ALTCODE'} = 1, $ConfigSub{'NTL_CRT_ALTCODE_SMALL'} = 0, $ConfigSub{'NTL_GF2X_NOINLINE'} = 1, $ConfigSub{'NTL_GF2X_ALTCODE'} = 0, $ConfigSub{'NTL_GF2X_ALTCODE1'} = 0, } else { die "Error: TUNE not in {auto,generic,x86,linux-s390x}"; } } } Process_TUNE(); # we call this once here and then optionally again later # if the TUNE flag is not set on the command line # and the architecture is recognized (right now, only # x86 and s390x are recognized) ######################################### if ($nowrite) { GenFiles(); exit 0; } ######################################### unlink "need-to-run-configure"; # this gets unlinked here and recreated upon normal # termination. The makefile checks for this. # This prevents leaving makefile and config.h in some # indeterminant state. #get some rudimentary info from compiler # language_standard: one of 0, 1997, 2011, 2014, 2017. # used to set -std= flag intelligently # cpu_type: one of x86, s390x, unknown # used to set TUNE intelligently # compiler_name: one of gcc, clang, icc, unknown # used to set floating point flags intelligently GenFiles(); CopyFiles(); RemoveProg("GenConfigInfo"); system("echo '*** building GenConfigInfo' >> CompilerOutput.log"); if(system("$MakeSub{'MAKE_PROG'} GenConfigInfo >> CompilerOutput.log 2>&1")) { print("Compilation failed\n"); print("See CompilerOutput.log for details\n"); die "Goodbye!"; } my $config_info = `./GenConfigInfo`; my ($compiler_name, $language_standard, $cpu_type, $os_name); ($compiler_name, $language_standard, $cpu_type, $os_name) = ($config_info =~ /\((.*?),(.*?),(.*?),(.*?)\)/) or die "Error: GenConfigInfo failed"; # convert to number $language_standard += 0 or Warning("__cplusplus not correctly defined"); print("compiler_name=$compiler_name\n"); print("language_standard=$language_standard\n"); print("cpu_type=$cpu_type\n"); print("os_name=$os_name\n\n"); if (!exists($Variable{'TUNE'})) { if ($cpu_type eq "x86") { $MakeSub{'TUNE'}='x86'; Process_TUNE(); print "setting TUNE=x86\n"; } elsif ($cpu_type eq "s390x" && $os_name eq "linux" && $compiler_name =~ /gcc|clang/) { $MakeSub{'TUNE'}='linux-s390x'; Process_TUNE(); print "setting TUNE=linux-s390x\n"; } } if (exists($Variable{'CXXAUTOFLAGS'})) { print("CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n"); GenFiles(); CopyFiles(); exit 0; } if ($min_std >= 2014) { if ($language_standard < 2014) { CheckFlag('-std=c++14'); } } elsif ($min_std >= 2011) { if ($language_standard < 2011) { CheckFlag('-std=c++11'); } } if ($pthread_flag) { CheckFlag('-pthread'); } if ($native_flag) { CheckFlag('-march=native'); } # disable floating-point optimizations that are not value safe # for most compilers, the default at optimzation '-O2' is to # disable such optimizations. icc is the big exception, # so we compile all of NTL with the "-fp-model precise" flag. # On older IA-32 machines, this also has the effect of preventing # calculations in "extended double" precision. if ($compiler_name eq 'icc') { CheckFlag('-fp-model precise'); } # logic to disable floating-point contractions (FMA) in quad_float.cpp. # This is an issue on machines with FMA instructions. # By default, gcc and icc allow contractions, while clang does not. sub CheckContract { return Exec("CheckContract"); } # on success, returns 1 and leaves flag set sub FixContract { my ($flag) = @_; print "*** checking $flag flag\n"; system("echo '*** checking $flag flag' >> CompilerOutput.log"); $MakeSub{'NOCONTRACT'} = $flag . ' ' . '-DNTL_CONTRACTION_FIXED'; my $result = CheckContract(); if ($result) { print " $flag works\n"; } else { print " $flag does not work\n"; $MakeSub{'NOCONTRACT'} = ''; } return $result; } if (!CheckContract()) { if (exists($Variable{'NOCONTRACT'})) { Warning("cannot disable floating point contraction"); } elsif ($compiler_name eq 'gcc') { FixContract('-ffp-contract=off') || FixContract('-mno-fused-madd') || # obsolete, but may work on older gcc's Warning("cannot disable floating point contraction"); } elsif ($compiler_name eq 'clang') { # this really should not be necessary with clang: the default # is no contractions FixContract('-ffp-contract=off') || Warning("cannot disable floating point contraction"); } elsif ($compiler_name eq 'icc') { # defining NTL_FP_CONTRACT_OFF will make the source # code use the pragma fp_contract(off) FixContract('-DNTL_FP_CONTRACT_OFF') || Warning("cannot disable floating point contraction"); } else { Warning("cannot disable floating point contraction"); } } # logic to check that threads and TLS are working...enable NTL_TLS_HACK # if necessary sub CheckThreads { return Exec("CheckThreads"); } if ($ConfigSub{'NTL_THREADS'}) { if (CheckThreads()) { print "*** threads are OK \n"; } else { if ($ConfigSub{'NTL_TLS_HACK'} == 0) { die "Error: threads are broken"; } $ConfigSub{'NTL_TLS_HACK'} = 0; if (CheckThreads()) { print "*** threads are OK with NTL_TLS_HACK=off\n"; } else { die "Error: threads are broken"; } } } GenFiles(); CopyFiles(); unlink "setup-phase"; # This will force make to run the setup phase system("touch need-to-run-configure") and die "Error: could not create need-to-run-configure"; print("\n"); print("CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n"); print("NOCONTRACT=\"$MakeSub{'NOCONTRACT'}\"\n"); print("\n"); print("generated makefile\n"); print("generated ../include/NTL/config.h\n"); print("generated ../include/NTL/ConfigLog.h\n"); exit 0; ntl-11.5.1/src/mfile0000644417616742025610000005073514064716022015775 0ustar gid-shoupvpug-gid-shoupv############################################################### # # First, choose a C++ compiler, and set compiler flags. # This is done by setting the variables CXX and CXXFLAGS. # ############################################################### CXX=@{CXX} # A C++ compiler, e.g., g++, CC, xlC CXXFLAGS=@{CXXFLAGS} # Flags for the C++ compiler CXXAUTOFLAGS=@{CXXAUTOFLAGS} # Flags for the C++ compiler, automatically generated by configuration script NOCONTRACT=@{NOCONTRACT} AR=@{AR} # command to make a library ARFLAGS=@{ARFLAGS} # arguments for AR RANLIB=@{RANLIB} # set to echo if you want to disable it completely LDFLAGS=@{LDFLAGS} # libraries for linking C++ programs LDLIBS=@{LDLIBS} # libraries for linking C++ programs CPPFLAGS=@{CPPFLAGS} # arguments for the C preprocessor LIBTOOL=@{LIBTOOL} # libtool command -- this is now built locally LIBTOOL_LINK_FLAGS=@{LIBTOOL_LINK_FLAGS} # flags to add to command line when building a shared library # mainly used to pass the argument "-no-undefined" on cygwin LIBTOOL_LINK_LIBS=@{LIBTOOL_LINK_LIBS} # libraries to add to the command line when building a shared library # mainly used to pass the argument "-lpthread", which NTL's # configure script will do "automagically" unless user overrides # that behavior DEF_PREFIX=@{DEF_PREFIX} PREFIX=@{PREFIX} LIBDIR=@{LIBDIR} INCLUDEDIR=@{INCLUDEDIR} DOCDIR=@{DOCDIR} # where to install NTL DESTDIR= # added to support standard package building techniques # that install into a "staging area" ############################################################### # # Second, if you want to use GMP (the GNU Multi-Precision library), # define the variables GMP_OPT_INCDIR, GMP_OPT_LIBDIR, GMP_OPT_LIB below. # You also will have to set either NTL_GMP_LIP or NTL_GMP_HACK # in the config.h file. # # Using GMP can lead to significant performance gains on some # platforms. You can obtain GMP from http://www.swox.com/gmp. # Once you unpack it into a directory, just execute # ./configure; make # in that directory. # ############################################################### GMP_PREFIX=@{GMP_PREFIX} GMP_INCDIR=@{GMP_INCDIR} # directory containing gmp.h if using GMP GMP_LIBDIR=@{GMP_LIBDIR} # directory containing libgmp.a if using GMP GMP_OPT_INCDIR=@{GMPI}-I$(GMP_INCDIR) # GMPI GMP_OPT_LIBDIR=@{GMPL}-L$(GMP_LIBDIR) # GMPL GMP_OPT_LIB=@{GMP}-lgmp # GMP # uncomment these if using GMP ############################################################### # # Third, if you want to use gf2x (a library for fast # multiplication over GF(2)[X]), you need to # define the variables GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, GF2X_OPT_LIB below. # You also will have to set NTL_GF2X_LIB # in the config.h file. # ############################################################### GF2X_PREFIX=@{GF2X_PREFIX} GF2X_INCDIR=@{GF2X_INCDIR} # directory containing gf2x.h if using gf2x GF2X_LIBDIR=@{GF2X_LIBDIR} # directory containing libgf2x.a GF2X_OPT_INCDIR=@{GF2XI}-I$(GF2X_INCDIR) # GF2X GF2X_OPT_LIBDIR=@{GF2XL}-L$(GF2X_LIBDIR) # GF2X GF2X_OPT_LIB=@{GF2X}-lgf2x # GF2X # uncomment these if using gf2x ############################################################### # # Fourth, if you do not want to run the wizard that automagically # sets some performace related flags in config.h, set the flag below. # ############################################################### WIZARD=@{WIZARD} # Set to off if you want to bypass the wizard; otherwise, set to on. ################################################################# # # That's it! You can ignore everything else in this file! # ################################################################# # object files OBJ=FFT.o FacVec.o GF2.o GF2E.o GF2EX.o GF2EXFactoring.o GF2X.o GF2X1.o \ GF2XFactoring.o GF2XVec.o GetTime.o GetPID.o HNF.o ctools.o LLL.o LLL_FP.o \ LLL_QP.o LLL_RR.o LLL_XD.o RR.o WordVector.o ZZ.o ZZVec.o ZZX.o ZZX1.o \ ZZXCharPoly.o ZZXFactoring.o ZZ_p.o ZZ_pE.o ZZ_pEX.o ZZ_pEXFactoring.o ZZ_pX.o \ ZZ_pX1.o ZZ_pXCharPoly.o ZZ_pXFactoring.o fileio.o lip.o lzz_p.o lzz_pE.o \ lzz_pEX.o lzz_pEXFactoring.o lzz_pX.o lzz_pX1.o lzz_pXCharPoly.o \ lzz_pXFactoring.o mat_GF2.o mat_GF2E.o mat_RR.o mat_ZZ.o mat_ZZ_p.o mat_ZZ_pE.o \ mat_lzz_p.o mat_lzz_pE.o mat_poly_ZZ.o mat_poly_ZZ_p.o mat_poly_lzz_p.o \ quad_float.o quad_float1.o tools.o vec_GF2.o vec_GF2E.o vec_RR.o vec_ZZ.o vec_ZZ_p.o \ vec_ZZ_pE.o vec_lzz_p.o vec_lzz_pE.o xdouble.o G_LLL_FP.o G_LLL_QP.o G_LLL_XD.o \ G_LLL_RR.o thread.o BasicThreadPool.o MatPrime.o pd_FFT.o # library source files SRC=FFT.cpp FacVec.cpp GF2.cpp GF2E.cpp GF2EX.cpp GF2EXFactoring.cpp GF2X.cpp \ GF2X1.cpp GF2XFactoring.cpp GF2XVec.cpp HNF.cpp ctools.cpp LLL.cpp LLL_FP.cpp \ LLL_QP.cpp LLL_RR.cpp LLL_XD.cpp RR.cpp WordVector.cpp ZZ.cpp ZZVec.cpp ZZX.cpp \ ZZX1.cpp ZZXCharPoly.cpp ZZXFactoring.cpp ZZ_p.cpp ZZ_pE.cpp ZZ_pEX.cpp \ ZZ_pEXFactoring.cpp ZZ_pX.cpp ZZ_pX1.cpp ZZ_pXCharPoly.cpp ZZ_pXFactoring.cpp \ fileio.cpp lip.cpp lzz_p.cpp lzz_pE.cpp lzz_pEX.cpp lzz_pEXFactoring.cpp \ lzz_pX.cpp lzz_pX1.cpp lzz_pXCharPoly.cpp lzz_pXFactoring.cpp mat_GF2.cpp \ mat_GF2E.cpp mat_RR.cpp mat_ZZ.cpp mat_ZZ_p.cpp mat_ZZ_pE.cpp mat_lzz_p.cpp \ mat_lzz_pE.cpp mat_poly_ZZ.cpp mat_poly_ZZ_p.cpp mat_poly_lzz_p.cpp \ quad_float.cpp quad_float1.cpp tools.cpp vec_GF2.cpp vec_GF2E.cpp vec_RR.cpp vec_ZZ.cpp \ vec_ZZ_p.cpp vec_ZZ_pE.cpp vec_lzz_p.cpp vec_lzz_pE.cpp xdouble.cpp \ G_LLL_FP.cpp G_LLL_QP.cpp G_LLL_XD.cpp G_LLL_RR.cpp thread.cpp \ BasicThreadPool.cpp MatPrime.cpp pd_FFT.cpp # library header files INCL=FFT.h FFT_impl.h FacVec.h GF2.h GF2E.h GF2EX.h GF2EXFactoring.h GF2X.h \ GF2XFactoring.h GF2XVec.h HNF.h ctools.h LLL.h RR.h WordVector.h \ ZZ.h ZZ_limbs.h sp_arith.h ZZVec.h ZZX.h ZZXFactoring.h ZZ_p.h ZZ_pE.h ZZ_pEX.h \ ZZ_pEXFactoring.h ZZ_pX.h ZZ_pXFactoring.h fileio.h lip.h lzz_p.h lzz_pE.h \ lzz_pEX.h lzz_pEXFactoring.h lzz_pX.h lzz_pXFactoring.h mat_GF2.h mat_GF2E.h \ mat_RR.h mat_ZZ.h mat_ZZ_p.h mat_ZZ_pE.h mat_lzz_p.h mat_lzz_pE.h mat_poly_ZZ.h \ mat_poly_ZZ_p.h mat_poly_lzz_p.h matrix.h pair.h vector.h pair_GF2EX_long.h \ pair_GF2X_long.h pair_ZZX_long.h pair_ZZ_pEX_long.h pair_ZZ_pX_long.h \ pair_lzz_pEX_long.h pair_lzz_pX_long.h quad_float.h tools.h vec_GF2.h \ vec_GF2E.h vec_GF2XVec.h vec_RR.h vec_ZZ.h vec_ZZVec.h vec_ZZ_p.h vec_ZZ_pE.h \ vec_double.h vec_long.h vec_lzz_p.h vec_lzz_pE.h vec_quad_float.h vec_vec_GF2.h \ vec_vec_GF2E.h vec_vec_RR.h vec_vec_ZZ.h vec_vec_ZZ_p.h vec_vec_ZZ_pE.h \ vec_vec_long.h vec_vec_lzz_p.h vec_vec_lzz_pE.h vec_xdouble.h xdouble.h \ config.h version.h new.h vec_ulong.h vec_vec_ulong.h SmartPtr.h \ Lazy.h LazyTable.h thread.h BasicThreadPool.h MatPrime.h PD.h pd_FFT.h \ linux_s390x.h # test data TD=BerlekampTestIn BerlekampTestOut CanZassTestIn CanZassTestOut \ ZZXFacTestIn ZZXFacTestOut MoreFacTestIn LLLTestIn LLLTestOut RRTestIn RRTestOut \ MatrixTestIn MatrixTestOut CharPolyTestIn \ CharPolyTestOut QuadTestIn QuadTestOut # test source files TS=QuickTest.cpp ZZTest.cpp SSMulTest.cpp ZZ_pXTest.cpp lzz_pXTest.cpp BerlekampTest.cpp \ CanZassTest.cpp ZZXFacTest.cpp MoreFacTest.cpp \ LLLTest.cpp subset.cpp MatrixTest.cpp mat_lzz_pTest.cpp \ CharPolyTest.cpp RRTest.cpp QuadTest.cpp GF2XTest.cpp GF2EXTest.cpp GF2EXGCDTest.cpp \ BitMatTest.cpp ZZ_pEXTest.cpp ZZ_pEXGCDTest.cpp lzz_pEXTest.cpp lzz_pEXGCDTest.cpp \ Timing.cpp ThreadTest.cpp ExceptionTest.cpp # aux source to help compute crossovers CROSS=GF2EXDivCross.cpp GF2EXGCDCross.cpp GF2EXKarCross.cpp GF2EXModCross.cpp # scripts SCRIPTS=MakeGetTime MakeGetPID MakeCheckFeatures ResetFeatures CopyFeatures \ TestScript dosify unixify RemoveProg configure DoConfig mfile cfile ppscript # auxilliary source MD=MakeDesc.cpp MakeDescAux.cpp newnames.cpp gen_gmp_aux.cpp gf2x_version_1_2_or_later_required.cpp GT=GetTime0.cpp GetTime1.cpp GetTime2.cpp GetTime3.cpp GetTime4.cpp GetTime5.cpp TestGetTime.cpp GP=GetPID1.cpp GetPID2.cpp TestGetPID.cpp CH=CheckCompile.cpp GenConfigInfo.cpp CheckContract.cpp CheckContractAux.cpp \ CheckThreads.cpp AUXPROGS = TestGetTime TestGetPID CheckFeatures CheckCompile GenConfigInfo CheckContract \ CheckThreads FEATURES=ALIGNED_ARRAY BUILTIN_CLZL LL_TYPE SSSE3 AVX PCLMUL AVX2 FMA AVX512F \ COPY_TRAITS1 COPY_TRAITS2 CHRONO_TIME MACOS_TIME POSIX_TIME AES_NI KMA # documentation DFILES=copying.txt BasicThreadPool.txt GF2.txt GF2E.txt GF2EX.txt \ GF2EXFactoring.txt GF2X.txt GF2XFactoring.txt GF2XVec.txt HNF.txt Lazy.txt \ LazyTable.txt LLL.txt RR.txt SmartPtr.txt ZZ.txt ZZ_limbs.txt ZZVec.txt ZZX.txt \ ZZXFactoring.txt ZZ_p.txt ZZ_pE.txt ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt \ ZZ_pXFactoring.txt conversions.txt flags.txt lzz_p.txt lzz_pE.txt lzz_pEX.txt \ lzz_pEXFactoring.txt lzz_pX.txt lzz_pXFactoring.txt mat_GF2.txt mat_GF2E.txt \ mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt mat_ZZ_pE.txt mat_lzz_p.txt mat_lzz_pE.txt \ mat_poly_ZZ.txt mat_poly_ZZ_p.txt mat_poly_lzz_p.txt matrix.txt pair.txt \ vector.txt quad_float.txt sedscript.txt tools.txt vec_GF2.txt vec_GF2E.txt \ vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt vec_lzz_p.txt vec_lzz_pE.txt \ xdouble.txt names.txt tour-ack.html tour-intro.html tour-time.html \ tour-changes.html tour-modules.html tour-unix.html tour-examples.html \ tour-roadmap.html tour-win.html tour-impl.html tour-struct.html tour.html \ tour-ex1.html tour-ex2.html tour-ex3.html tour-ex4.html tour-ex5.html \ tour-ex6.html tour-ex7.html arrow1.gif arrow2.gif arrow3.gif tour-gmp.html \ tour-gf2x.html tour-tips.html config.txt version.txt TXFILES=GF2.txt GF2E.txt GF2EX.txt GF2EXFactoring.txt GF2X.txt \ GF2XFactoring.txt GF2XVec.txt HNF.txt Lazy.txt LazyTable.txt LLL.txt RR.txt \ SmartPtr.txt ZZ.txt ZZ_limbs.txt ZZVec.txt ZZX.txt ZZXFactoring.txt ZZ_p.txt ZZ_pE.txt \ ZZ_pEX.txt ZZ_pEXFactoring.txt ZZ_pX.txt ZZ_pXFactoring.txt lzz_p.txt \ lzz_pE.txt lzz_pEX.txt lzz_pEXFactoring.txt lzz_pX.txt lzz_pXFactoring.txt \ mat_GF2.txt mat_GF2E.txt mat_RR.txt mat_ZZ.txt mat_ZZ_p.txt mat_ZZ_pE.txt \ mat_lzz_p.txt mat_lzz_pE.txt mat_poly_ZZ.txt mat_poly_ZZ_p.txt \ mat_poly_lzz_p.txt matrix.txt pair.txt quad_float.txt tools.txt vec_GF2.txt \ vec_GF2E.txt vec_RR.txt vec_ZZ.txt vec_ZZ_p.txt vec_ZZ_pE.txt vec_lzz_p.txt \ vec_lzz_pE.txt vector.txt version.txt xdouble.txt BasicThreadPool.txt HTFILES=GF2.cpp.html GF2E.cpp.html GF2EX.cpp.html GF2EXFactoring.cpp.html \ GF2X.cpp.html GF2XFactoring.cpp.html GF2XVec.cpp.html HNF.cpp.html \ Lazy.cpp.html LazyTable.cpp.html LLL.cpp.html RR.cpp.html SmartPtr.cpp.html \ ZZ.cpp.html ZZ_limbs.cpp.html ZZVec.cpp.html ZZX.cpp.html ZZXFactoring.cpp.html ZZ_p.cpp.html \ ZZ_pE.cpp.html ZZ_pEX.cpp.html ZZ_pEXFactoring.cpp.html ZZ_pX.cpp.html \ ZZ_pXFactoring.cpp.html lzz_p.cpp.html lzz_pE.cpp.html lzz_pEX.cpp.html \ lzz_pEXFactoring.cpp.html lzz_pX.cpp.html lzz_pXFactoring.cpp.html \ mat_GF2.cpp.html mat_GF2E.cpp.html mat_RR.cpp.html mat_ZZ.cpp.html \ mat_ZZ_p.cpp.html mat_ZZ_pE.cpp.html mat_lzz_p.cpp.html mat_lzz_pE.cpp.html \ mat_poly_ZZ.cpp.html mat_poly_ZZ_p.cpp.html mat_poly_lzz_p.cpp.html \ matrix.cpp.html pair.cpp.html quad_float.cpp.html tools.cpp.html \ vec_GF2.cpp.html vec_GF2E.cpp.html vec_RR.cpp.html vec_ZZ.cpp.html \ vec_ZZ_p.cpp.html vec_ZZ_pE.cpp.html vec_lzz_p.cpp.html vec_lzz_pE.cpp.html \ vector.cpp.html version.cpp.html xdouble.cpp.html BasicThreadPool.cpp.html DOC = $(DFILES) $(HTFILES) TFT-time.jpg zmulrat.jpg flintrat.jpg # test program executables PROGS=QuickTest ZZTest SSMulTest ZZ_pXTest lzz_pXTest BerlekampTest CanZassTest \ ZZXFacTest MoreFacTest LLLTest \ BitMatTest MatrixTest mat_lzz_pTest CharPolyTest RRTest QuadTest GF2XTest \ GF2EXTest GF2EXGCDTest subset ZZ_pEXTest ZZ_pEXGCDTest lzz_pEXTest lzz_pEXGCDTest \ Timing ThreadTest # things to save to a tar file SFILES=$(SRC) $(SCRIPTS) $(MD) $(GT) $(GP) $(CH) $(TS) $(TD) $(CROSS) mach_desc.win \ Poly1TimeTest.cpp Poly2TimeTest.cpp Poly3TimeTest.cpp GF2XTimeTest.cpp \ InitSettings.cpp DispSettings.cpp WizardAux Wizard ################################################################# # # Rules for compiling the library # ################################################################# NTL_INCLUDE = -I../include -I. # NTL needs this to find its include files COMPILE = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(CXXAUTOFLAGS) -c LINK = $(CXX) $(NTL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(CXXAUTOFLAGS) $(LDFLAGS) # 'make' or 'make all' does a complete make, including additional # setup not done in configure. # The file setup-phase is removed by the configure script # when it terminates successfully. # The file need-to-run-configure is removed by the configure script # before making any changes to makefile/config.h and is recreated # when it terminates successfully. all: setup-phase $(MAKE) ntl.a setup-phase: need-to-run-configure $(MAKE) clobber $(MAKE) setup1 $(MAKE) setup2 $(MAKE) setup3 $(MAKE) setup4 touch setup-phase # setup1 generates the file ../incluse/NTL/mach_desc.h setup1: $(COMPILE) MakeDescAux.cpp $(LINK) -o MakeDesc MakeDesc.cpp MakeDescAux.o $(LDLIBS) ./MakeDesc mv mach_desc.h ../include/NTL/mach_desc.h # setup2 does some dynamic checks for GetTime, GetPID, and other features setup2: echo "*** CheckFeatures log ***" > CheckFeatures.log sh MakeGetTime "$(LINK)" "$(LDLIBS)" sh MakeGetPID "$(LINK)" "$(LDLIBS)" sh MakeCheckFeatures "$(FEATURES)" "$(LINK)" "$(LDLIBS)" # NOTE: to add a feature XXX: # * add a program CheckXXX.cpp which returns 0 if XXX works, -1 otherwise # * add XXX to the FEATURES variable # setup3 generates the file ../include/NTL/gmp_aux.h # The file ../include/NTL/gmp_aux.h is included in ../include/NTL/lip.h # when NTL_GMP_LIP is set. # When this flag is not set, an empty files produced. # This also checks that the right version of gf2x library. setup3: $(LINK) $(GMP_OPT_INCDIR) -o gen_gmp_aux gen_gmp_aux.cpp $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) ./gen_gmp_aux > ../include/NTL/gmp_aux.h $(LINK) $(GF2X_OPT_INCDIR) -o gf2x_version_1_2_or_later_required gf2x_version_1_2_or_later_required.cpp $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) # setup4 runs the wizard setup4: sh Wizard $(WIZARD) "$(MAKE)" "$(FEATURES)" ntl.a: $(OBJ) @{LSTAT} $(AR) $(ARFLAGS) ntl.a $(OBJ) #LSTAT @{LSTAT} - $(RANLIB) ntl.a #LSTAT @{LSHAR} $(LIBTOOL) --tag=CXX --mode=link $(LINK) $(LIBTOOL_LINK_FLAGS) -o libntl.la $(OBJ:.o=.lo) $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) $(LIBTOOL_LINK_LIBS) -rpath $(LIBDIR) -version-info `cat VERSION_INFO` #LSHAR @{LSTAT}LCOMP= #LSTAT @{LSHAR}LCOMP=$(LIBTOOL) --tag=CXX --mode=compile #LSHAR lip.o: lip.cpp $(LCOMP) $(COMPILE) $(GMP_OPT_INCDIR) lip.cpp GF2X.o: GF2X.cpp $(LCOMP) $(COMPILE) $(GF2X_OPT_INCDIR) GF2X.cpp quad_float.o: quad_float.cpp $(LCOMP) $(COMPILE) $(NOCONTRACT) quad_float.cpp pd_FFT.o: pd_FFT.cpp $(LCOMP) $(COMPILE) $(NOCONTRACT) pd_FFT.cpp CheckCompile: CheckCompile.cpp $(LINK) -o CheckCompile CheckCompile.cpp $(LDLIBS) GenConfigInfo: GenConfigInfo.cpp $(LINK) -o GenConfigInfo GenConfigInfo.cpp $(LDLIBS) CheckContract: CheckContract.cpp CheckContractAux.cpp $(LINK) $(NOCONTRACT) -o CheckContract CheckContract.cpp CheckContractAux.cpp $(LDLIBS) CheckThreads: CheckThreads.cpp $(LINK) -o CheckThreads CheckThreads.cpp $(LDLIBS) .cpp.o: $(LCOMP) $(COMPILE) $< .cpp: @{LSTAT} $(LINK) -o $@ $< ntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(GF2X_OPT_LIBDIR) $(GF2X_OPT_LIB) $(LDLIBS) #LSTAT @{LSHAR} $(LIBTOOL) --tag=CXX --mode=link $(LINK) -o $@ $< libntl.la #LSHAR ################################################################# # # Rule for running tests # make check runs a series of tests # ################################################################# check: sh RemoveProg $(PROGS) $(MAKE) QuickTest ./QuickTest sh RemoveProg QuickTest sh TestScript "$(MAKE)" ################################################################# # # Rule for installing # make install just does a simple copy of the include file # and library. The -p option is used to preserve file attributes. # This helps avoid some problems (especially when copying ntl.a). # Also, an attempt is made to make everything that is # installed readable by everyone. # # make uninstall removes these files # ################################################################# install: mkdir -p -m 755 $(DESTDIR)$(INCLUDEDIR) rm -rf $(DESTDIR)$(INCLUDEDIR)/NTL mkdir -m 755 $(DESTDIR)$(INCLUDEDIR)/NTL cp -p ../include/NTL/*.h $(DESTDIR)$(INCLUDEDIR)/NTL - chmod -R a+r $(DESTDIR)$(INCLUDEDIR)/NTL mkdir -p -m 755 $(DESTDIR)$(DOCDIR) rm -rf $(DESTDIR)$(DOCDIR)/NTL mkdir -m 755 $(DESTDIR)$(DOCDIR)/NTL cp -p ../doc/*.txt $(DESTDIR)$(DOCDIR)/NTL cp -p ../doc/*.html $(DESTDIR)$(DOCDIR)/NTL cp -p ../doc/*.gif $(DESTDIR)$(DOCDIR)/NTL - chmod -R a+r $(DESTDIR)$(DOCDIR)/NTL mkdir -p -m 755 $(DESTDIR)$(LIBDIR) @{LSTAT} cp -p ntl.a $(DESTDIR)$(LIBDIR)/libntl.a #LSTAT @{LSTAT} - chmod a+r $(DESTDIR)$(LIBDIR)/libntl.a #LSTAT @{LSHAR} $(LIBTOOL) --mode=install cp -p libntl.la $(DESTDIR)$(LIBDIR) #LSHAR uninstall: @{LSTAT} rm -f $(LIBDIR)/libntl.a #LSTAT @{LSHAR} $(LIBTOOL) --mode=uninstall rm -f $(LIBDIR)/libntl.la #LSHAR rm -rf $(INCLUDEDIR)/NTL rm -rf $(DOCDIR)/NTL ################################################################# # # Rules for cleaning up # # make clobber removes *everything* created by make, # but it does not restore config.h to its default. # # make clean tidies up a bit # ################################################################# clobber: rm -f ntl.a mach_desc.h ../include/NTL/mach_desc.h GetTime.cpp GetPID.cpp sh ResetFeatures '..' "$(FEATURES)" rm -f ../include/NTL/gmp_aux.h sh RemoveProg $(PROGS) MakeDesc $(AUXPROGS) gen_gmp_aux gf2x_version_1_2_or_later_required rm -f *.o rm -rf small rm -f cfileout mfileout rm -rf .libs *.lo libntl.la rm -f setup-phase clean: sh RemoveProg $(PROGS) MakeDesc $(AUXPROGS) gen_gmp_aux gf2x_version_1_2_or_later_required rm -f *.o rm -rf small @{LSHAR} - $(LIBTOOL) --mode=clean rm -f libntl.la *.lo #LSHAR wclean: rm -f *.o ################################################################# # # Rules for making tar and zip files # # make libtool-gen-origin generates the directory # libtool-origin used to include in the distribution # - this only needs to be run very occasionally, to keep # libtool relatively up-to-date # - it must be run on a machine with autotools # # make ppdoc creates pretty-printed versions of some documentation # - run before make package or make winpack # # make package creates a tar.gz file suitable for Unix # # make winpack creates a zip file suitable for Windows # ################################################################# libtool-gen-origin: rm -rf libtool-origin && \ cp -R libtool-seed libtool-origin && \ cd libtool-origin && autoreconf -fiv && rm -rf autom4te.cache ppdoc: sh ppscript "$(TXFILES)" ppclean: rm -f ../doc/*.cpp package: sh unixify "$(SFILES) DIRNAME WINDIR VERSION_INFO NOTES" "$(INCL)" "$(DOC)" "$(FEATURES)" rm -rf `cat DIRNAME` rm -f `cat DIRNAME`.tar rm -f `cat DIRNAME`.tar.gz mv unix `cat DIRNAME` chmod -R a+rX `cat DIRNAME` tar -cvf `cat DIRNAME`.tar `cat DIRNAME` gzip `cat DIRNAME`.tar rm -rf `cat DIRNAME` winpack: ./configure --nowrite NTL_GMP_LIP=off NTL_TLS_HACK=off sh dosify "$(SRC)" "$(INCL)" "$(DOC)" "$(TS)" "$(TD)" "$(FEATURES)" rm -rf `cat WINDIR` rm -f `cat WINDIR`.zip mv dos `cat WINDIR` chmod -R a+rX `cat WINDIR` find ./`cat WINDIR` '!' '(' -name '*.gif' -o -name '*.jpg' ')' -print | zip -l `cat WINDIR` -@ find ./`cat WINDIR` -name '*.gif' -o -name '*.jpg' -print | zip -u `cat WINDIR` -@ rm -rf `cat WINDIR` ###################################################################### # # config wizard related stuff # ###################################################################### WOBJ=FFT.o GetTime.o GetPID.o ctools.o ZZ.o ZZVec.o ZZ_p.o ZZ_pX.o ZZ_pX1.o \ lip.o tools.o vec_ZZ.o vec_ZZ_p.o GF2.o WordVector.o vec_GF2.o GF2X.o GF2X1.o \ thread.o BasicThreadPool.o fileio.o @{LSHAR}wntl.a: LCOMP= #LSHAR wntl.a: $(WOBJ) $(AR) $(ARFLAGS) wntl.a $(WOBJ) - $(RANLIB) wntl.a Poly1TimeTest: $(LINK) -o Poly1TimeTest Poly1TimeTest.cpp wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) Poly2TimeTest: $(LINK) -o Poly2TimeTest Poly2TimeTest.cpp wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) Poly3TimeTest: $(LINK) -o Poly3TimeTest Poly3TimeTest.cpp wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) GF2XTimeTest: $(LINK) -o GF2XTimeTest GF2XTimeTest.cpp wntl.a $(GMP_OPT_LIBDIR) $(GMP_OPT_LIB) $(LDLIBS) InitSettings: $(LINK) -o InitSettings InitSettings.cpp $(LDLIBS) DispSettings: $(LINK) -o DispSettings DispSettings.cpp $(LDLIBS) ntl-11.5.1/src/cfile0000644417616742025610000002710014064716022015751 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_config__H #define NTL_config__H /************************************************************************* NTL Configuration File ---------------------- This file is automatically generated by the configure script. You can also edit this file by hand, but that is not generally recommended. To set a flag, just replace the pre-processor directive 'if 0' by 'if 1' for that flag, which causes the appropriate macro to be defined. Of course, to unset a flag, just replace the 'if 1' by an 'if 0'. *************************************************************************/ /************************************************************************* * * Basic Configuration Options * *************************************************************************/ /* None of these flags are set by the configuration wizard; * they must be set by hand, before installation begins. */ #if @{NTL_LEGACY_NO_NAMESPACE} #define NTL_LEGACY_NO_NAMESPACE /* * By default, NTL components are declared inside the namespace NTL. * Set this flag if you want to instead have these components * declared in the global namespace. This is for backward * compatibility only -- not recommended. * */ #endif #if @{NTL_LEGACY_INPUT_ERROR} #define NTL_LEGACY_INPUT_ERROR /* * Also for backward compatibility. Set if you want input * operations to abort on error, instead of just setting the * "fail bit" of the input stream. * */ #endif #if @{NTL_TLS_HACK} #define NTL_TLS_HACK /* Set if you want to compile NTL with "TLS hack" * */ #endif #if @{NTL_THREADS} #define NTL_THREADS /* Set if you want to compile NTL as a thread-safe library. * */ #endif #if @{NTL_EXCEPTIONS} #define NTL_EXCEPTIONS /* Set if you want to compile NTL with exceptions enabled * */ #endif #if @{NTL_THREAD_BOOST} #define NTL_THREAD_BOOST /* Set if you want to compile NTL to exploit threads internally. * */ #endif #if @{NTL_GMP_LIP} #define NTL_GMP_LIP /* * Use this flag if you want to use GMP as the long integer package. * This can result in significantly faster code on some platforms. * It requires that the GMP package (version >= 3.1) has already been * installed. You will also have to set the variables GMP_OPT_INCDIR, * GMP_OPT_LIBDIR, GMP_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GMP_LIP=on * to that script. * * Beware that setting this flag can break some very old NTL codes. * * You may also have to edit the makefile to modify the variables * GMP_OPT_INCDIR, GMP_OPT_LIBDIR, and GMP_OPT_LIB. */ #endif #if @{NTL_GF2X_LIB} #define NTL_GF2X_LIB /* * Use this flag if you want to use the gf2x library for * faster GF2X arithmetic. * This can result in significantly faster code, especially * when working with polynomials of huge degree. * You will also have to set the variables GF2X_OPT_INCDIR, * GF2X_OPT_LIBDIR, GF2X_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GF2X_LIB=on * to that script. * * You may also have to edit the makefile to modify the variables * GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, and GF2X_OPT_LIB. */ #endif #if @{NTL_STD_CXX11} #define NTL_STD_CXX11 /* * Set this flag if you want to enable C++11 features within NTL. */ #endif #if @{NTL_STD_CXX14} #define NTL_STD_CXX14 /* * Set this flag if you want to enable C++14 features within NTL. */ #endif #if @{NTL_DISABLE_MOVE_ASSIGN} #define NTL_DISABLE_MOVE_ASSIGN /* * Set this flag if you want to disable move assignment * operators for vectors (and, by extension, polynomials) * and matrices. */ #endif #if @{NTL_DISABLE_MOVE} #define NTL_DISABLE_MOVE /* * This flag disables all move constructors and assignments. */ #endif #if @{FLAG_UNSIGNED_LONG_LONG_TYPE} #define NTL_UNSIGNED_LONG_LONG_TYPE @{NTL_UNSIGNED_LONG_LONG_TYPE} /* * NTL_UNSIGNED_LONG_LONG_TYPE will be used * to declare 'double word' unsigned integer types. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'unsigned long long'. * */ #endif #if @{NTL_CLEAN_INT} #define NTL_CLEAN_INT /* * This will disallow the use of some non-standard integer arithmetic * that may improve performance somewhat. * */ #endif #if @{NTL_CLEAN_PTR} #define NTL_CLEAN_PTR /* * This will disallow the use of some non-standard pointer arithmetic * that may improve performance somewhat. * */ #endif #if @{NTL_SAFE_VECTORS} #define NTL_SAFE_VECTORS /* * This will compile NTL in "safe vector" mode, only assuming * the relocatability property for trivial types and types * explicitly declared relocatable. See vector.txt for more details. */ #endif #if @{NTL_ENABLE_AVX_FFT} #define NTL_ENABLE_AVX_FFT /* * This will compile NTL in a way that enables an AVX implemention * of the small-prime FFT. */ #endif #if @{NTL_AVOID_AVX512} #define NTL_AVOID_AVX512 /* * This will compile NTL in a way that avoids 512-bit operations, * even if AVX512 is available. */ #endif #if @{NTL_RANGE_CHECK} #define NTL_RANGE_CHECK /* * This will generate vector subscript range-check code. * Useful for debugging, but it slows things down of course. * */ #endif #if @{NTL_NO_INIT_TRANS} #define NTL_NO_INIT_TRANS /* * Without this flag, NTL uses a special code sequence to avoid * copying large objects in return statements. However, if your * compiler optimizes away the return of a *named* local object, * this is not necessary, and setting this flag will result * in *slightly* more compact and efficient code. Although * the emeriging C++ standard allows compilers to perform * this optimization, I know of none that currently do. * Most will avoid copying *temporary* objects in return statements, * and NTL's default code sequence exploits this fact. * */ #endif #if @{NTL_X86_FIX} #define NTL_X86_FIX /* * Forces the "x86 floating point fix", overriding the default behavior. * By default, NTL will apply the "fix" if it looks like it is * necessary, and if knows how to fix it. * The problem addressed here is that x86 processors sometimes * run in a mode where FP registers have more precision than doubles. * This will cause code in quad_float.cpp some trouble. * NTL can normally correctly detect the problem, and fix it, * so you shouldn't need to worry about this or the next flag. * */ #elif @{NTL_NO_X86_FIX} #define NTL_NO_X86_FIX /* * Forces no "x86 floating point fix", overriding the default behavior. */ #endif #if @{NTL_LEGACY_SP_MULMOD} #define NTL_LEGACY_SP_MULMOD /* Forces legacy single-precision MulMod implementation. */ #endif #if @{NTL_DISABLE_LONGDOUBLE} #define NTL_DISABLE_LONGDOUBLE /* Explicitly disables us of long double arithmetic */ #endif #if @{NTL_DISABLE_LONGLONG} #define NTL_DISABLE_LONGLONG /* Explicitly disables us of long long arithmetic */ #endif #if @{NTL_DISABLE_LL_ASM} #define NTL_DISABLE_LL_ASM /* Explicitly disables us of inline assembly as a replacement * for long lobg arithmetic. */ #endif #if @{NTL_MAXIMIZE_SP_NBITS} #define NTL_MAXIMIZE_SP_NBITS /* Allows for 62-bit single-precision moduli on 64-bit platforms. * By default, such moduli are restricted to 60 bits, which * usually gives slightly better performance across a range of * of parameters. */ #endif /************************************************************************* * * Performance Options * *************************************************************************/ /* There are three strategies to implmement single-precision * modular multiplication with preconditioning (see the MulModPrecon * function in the ZZ module): the default and NTL_SPMM_ULL. * This plays a crucial role in the "small prime FFT" used to * implement polynomial arithmetic, and in other CRT-based methods * (such as linear algebra over ZZ), as well as polynomial and matrix * arithmetic over zz_p. */ #if @{NTL_SPMM_ULL} #define NTL_SPMM_ULL /* This also causes an "all integer" * implementation of MulModPrecon to be used. * It us usually a faster implementation, * but it is not enturely portable. * It relies on double-word unsigned multiplication * (see NTL_UNSIGNED_LONG_LONG_TYPE above). * */ #endif /* * The following two flags provide additional control for how the * FFT modulo single-precision primes is implemented. */ #if @{NTL_FFT_BIGTAB} #define NTL_FFT_BIGTAB /* * Precomputed tables are used to store all the roots of unity * used in FFT computations. * */ #endif #if @{NTL_FFT_LAZYMUL} #define NTL_FFT_LAZYMUL /* * When set, a "lazy multiplication" strategy due to David Harvey: * see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". * */ #endif #if @{NTL_AVOID_BRANCHING} #define NTL_AVOID_BRANCHING /* * With this option, branches are replaced at several * key points with equivalent code using shifts and masks. * It may speed things up on machines with * deep pipelines and high branch penalities. * This flag mainly affects the implementation of the * single-precision modular arithmetic routines. * */ #endif #if @{NTL_TBL_REM} #define NTL_TBL_REM /* * * With this flag, some divisions are avoided in the * ZZ_pX multiplication routines. * */ #endif #if @{NTL_CRT_ALTCODE} #define NTL_CRT_ALTCODE /* * Employs an alternative CRT strategy. * Only relevant with GMP. * Seems to be marginally faster on some x86_64 platforms. * */ #endif #if @{NTL_CRT_ALTCODE_SMALL} #define NTL_CRT_ALTCODE_SMALL /* * Employs an alternative CRT strategy for small moduli. * Only relevant with GMP. * Seems to be marginally faster on some x86_64 platforms. * */ #endif #if @{NTL_GF2X_ALTCODE} #define NTL_GF2X_ALTCODE /* * With this option, the default strategy for implmenting low-level * GF2X multiplication is replaced with an alternative strategy. * This alternative strategy seems to work better on RISC machines * with deep pipelines and high branch penalties (like a powerpc), * but does no better (or even worse) on x86s. * */ #elif @{NTL_GF2X_ALTCODE1} #define NTL_GF2X_ALTCODE1 /* * Yest another alternative strategy for implementing GF2X * multiplication. * */ #endif #if @{NTL_GF2X_NOINLINE} #define NTL_GF2X_NOINLINE /* * By default, the low-level GF2X multiplication routine in inlined. * This can potentially lead to some trouble on some platforms, * and you can override the default by setting this flag. * */ #endif #if @{NTL_RANDOM_AES256CTR} #define NTL_RANDOM_AES256CTR /* * By default, the random-number generator is based on ChaCha20. * From a performance perspective, this choice may not be optimal * for platforms featuring AES hardware support. * By setting this flag you can override the default and use an * AES-256-CTR based random-number generator. * */ #endif /* sanity checks */ #if (defined(NTL_THREAD_BOOST) && !defined(NTL_THREADS)) #error "NTL_THREAD_BOOST defined but not NTL_THREADS" #endif #if (defined(NTL_THREADS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_THREADS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif #if (defined(NTL_EXCEPTIONS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_EXCEPTIONS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif #if (defined(NTL_SAFE_VECTORS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_SAFE_VECTORS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif @{WIZARD_HACK} #endif ntl-11.5.1/src/ppscript0000644417616742025610000000046614064716022016541 0ustar gid-shoupvpug-gid-shoupv#!/bin/bash VIM=$HOME/Applications/MacVim.app/Contents/bin/mvim cd ../doc for i in $* do name=`basename $i .txt` cp $name.txt $name.cpp $VIM $name.cpp '+set nu!' '+let c_no_curly_error=1' '+syntax off' '+syntax on' '+TOhtml' '+:1,$s/.*@anchor{\(.*\)}.*/<\/a>/' '+w' '+qa!' done ntl-11.5.1/src/MakeDesc.cpp0000644417616742025610000006755414064716022017145 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include #include #include using namespace std; #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) #define GNUC_INTEL (1) #else #define GNUC_INTEL (0) #endif int val_int(int x); unsigned int val_uint(unsigned int x); long val_long(long x); unsigned long val_ulong(unsigned long x); size_t val_size_t(size_t x); double val_double(double x); long double val_ldouble(double x); void touch_int(int* x); void touch_uint(unsigned int* x); void touch_long(long* x); void touch_ulong(unsigned long* x); void touch_size_t(size_t* x); void touch_double(double* x); void touch_ldouble(long double* x); double sum_double(double *x, long n); double fma_test(double a, double b, double c); double reassoc_test(double a, double b, double c, double d); double power2(long k); long FMADetected(long dp) { double x = power2(0) + power2(dp-1); double y = power2(0) + power2(dp-1); touch_double(&x); touch_double(&y); double z = x*y; touch_double(&z); z = -z; touch_double(&z); double lo = fma_test(x, y, z); return lo != 0; } long ReassocDetected(long dp) { double a = power2(0) + power2(dp-1); double b = power2(0) - power2(dp-1); double c = power2(0) + power2(dp-1); double d = power2(0) + power2(dp-1); touch_double(&a); touch_double(&b); touch_double(&c); touch_double(&d); double e = reassoc_test(a, b, c, d); touch_double(&e); double f = power2(dp+1); touch_double(&f); return e != f; } long DoubleRounding(long dp) { double a = power2(dp-1) + 1; double b = (power2(dp)-1)/power2(dp+1); double vec[2]; vec[0] = a; vec[1] = b; double sum = sum_double(vec, 2); touch_double(&sum); if (sum != a) return 1; else return 0; } long DoublePrecision() { double eps, one, res; long k; one = val_double(1.0); eps = val_double(1.0); k = 0; do { double tmp; k++; eps *= 1.0/2.0; tmp = 1.0 + eps; touch_double(&tmp); res = tmp - one; } while (res == eps); return k; } long LongDoublePrecision() { long double eps, one, res; long k; one = val_ldouble(1.0); eps = val_ldouble(1.0); k = 0; do { long double tmp; k++; eps *= 1.0/2.0; tmp = 1.0 + eps; touch_ldouble(&tmp); res = tmp - one; } while (res == eps && k < 500); // if k >= 500, then most likely this is some // weird double/double implementation. // We also check what numeric_limits says about long doubles. if (k >= 500 || !numeric_limits::is_iec559) k = 0; return k; } void print2k(FILE *f, long k, long bpl) { long m, l; long first; if (k <= 0) { fprintf(f, "((double) 1.0)"); return; } m = bpl - 2; first = 1; fprintf(f, "("); while (k > 0) { if (k > m) l = m; else l = k; k = k - l; if (first) first = 0; else fprintf(f, "*"); fprintf(f, "((double)(1L<<%ld))", l); } fprintf(f, ")"); } void print2k_WD(FILE *f, long k, long bpl) { long m, l; long first; if (k <= 0) { fprintf(f, "(wide_double(1L))"); return; } m = bpl - 2; first = 1; fprintf(f, "("); while (k > 0) { if (k > m) l = m; else l = k; k = k - l; if (first) first = 0; else fprintf(f, "*"); fprintf(f, "(wide_double(1L<<%ld))", l); } fprintf(f, ")"); } void print_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); } fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " b = bp[i];\\\n"); fprintf(f, " "); } fprintf(f, " lo = A[b & %lu]; ", mask); fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); for (i = 2*k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); } if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[b >> %ld]; ", n-chop); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " if (a >> %ld) ", n1-i); else fprintf(f, " if ((a >> %ld) & 1) ", n1-i); /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ fprintf(f, "hi ^= ((b & 0x%lxUL) >> %ld);\\\n", mask2, i); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1 || fn == 3) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } /* * This generates anternative code that runs significantly faster * on some machines, like a PowerPC (and probably other RISC machines). * It makes it easier for the compiler to schedule instrucyions better, * and it avoids branches. It seems like this does not help * on x86 machines (and can even make things worse). */ void print_alt_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_ALT_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0;\\\n"); } fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " const _ntl_ulong b = bp[i];\\\n"); } for (i = k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong t%ld = A[(b >> %ld) & %lu]; \\\n", i, i, mask); } if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong t%ld = A[b >> %ld]; \\\n", n-chop, n-chop); if (fn > 0) fprintf(f, " "); fprintf(f, " const _ntl_ulong lo = A[b & %lu] \\\n", mask); for (i = k; i < n; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " ^ (t%ld << %ld)", i, i); if (i == n - chop) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); } for (i = k; i < n; i += k) { if (fn > 0) fprintf(f, " "); if (i == k) fprintf(f, " const _ntl_ulong hi = "); else fprintf(f, " ^ "); fprintf(f, "(t%ld >> %ld)", i, n1-i); if (i == n - chop && short_flag) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); } mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", mask2, i, n1-1); else { fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", mask2, i, n1-i); } if (i == k-1) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } void print_alt1_mul_body(FILE *f, long n1, long k, long fn, long half_flag, long short_flag) { long n, i, chop, r; unsigned long mask, mask2; if (half_flag) n = n1/2; else n = n1; chop = n % k; /* first block */ if (chop == 0) chop = k; r = n - k; mask = (1UL << k) - 1UL; fprintf(f, "\n\n#define NTL_ALT1_"); if (half_flag) fprintf(f, "HALF_"); if (short_flag) fprintf(f, "SHORT_"); fprintf(f, "BB_MUL_CODE%ld \\\n", fn); if (fn > 0) /* Mul1/AddMul1 */ { fprintf(f, " long i;\\\n"); fprintf(f, " _ntl_ulong carry = 0, b;\\\n"); } fprintf(f, " _ntl_ulong hi, lo, t;\\\n"); fprintf(f, " _ntl_ulong A[%ld];\\\n", 1L << k); fprintf(f, " A[0] = 0;\\\n"); fprintf(f, " A[1] = a;\\\n"); for (i = 2; i < (1L << k); i++) { if (i % 2 == 0) fprintf(f, " A[%ld] = A[%ld] << 1;\\\n", i, i / 2); else fprintf(f, " A[%ld] = A[%ld] ^ A[1];\\\n", i, i - 1); } if (fn > 0) { fprintf(f, " for (i = 0; i < sb; i++) {\\\n"); fprintf(f, " b = bp[i];\\\n"); fprintf(f, " "); } fprintf(f, " lo = A[b & %lu]; ", mask); fprintf(f, "t = A[(b >> %ld) & %lu]; ", k, mask); fprintf(f, "hi = t >> %ld; lo ^= t << %ld;\\\n", n1-k, k); for (i = 2*k; i < n - chop; i += k) { if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[(b >> %ld) & %lu]; ", i, mask); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); } if (fn > 0) fprintf(f, " "); fprintf(f, " t = A[b >> %ld]; ", n-chop); fprintf(f, "hi ^= t >> %ld; lo ^= t << %ld;\\\n", n1-i, i); mask = 0; for (i = 0; i < n; i += k) mask |= 1UL << i; mask = ~mask; if (half_flag) mask &= (1UL << n) - 1UL; mask2 = mask; if (!short_flag) { for (i = 1; i < k; i++) { /* bit n1-i from a was not considered in blocks of k bits from b for index j >= i */ if (fn > 0) fprintf(f, " "); if (i == 1) fprintf(f, " hi ^= (((b & 0x%lxUL) >> %ld) & (-(a >> %ld)))", mask2, i, n1-1); else { fprintf(f, " ^ (((b & 0x%lxUL) >> %ld) & (-((a >> %ld) & 1UL)))", mask2, i, n1-i); } if (i == k-1) fprintf(f, ";\\\n"); else fprintf(f, "\\\n"); mask2 = (mask2 << 1) & mask; } } if (fn > 0) fprintf(f, " "); if (fn == 0) { fprintf(f, " c[0] = lo; "); fprintf(f, " c[1] = hi;\\\n"); } else if (fn == 1 || fn == 3) { fprintf(f, " cp[i] = carry ^ lo; "); fprintf(f, " carry = hi;\\\n"); } else if (fn == 2) { fprintf(f, " cp[i] ^= (carry ^ lo); "); fprintf(f, " carry = hi;\\\n"); } if (fn > 0) { fprintf(f, " }\\\n"); if (fn == 1 || fn == 3) fprintf(f, " cp[sb] = carry;\\\n"); else fprintf(f, " cp[sb] ^= carry;\\\n"); } fprintf(f, "\n\n\n"); } void print_BB_mul_code(FILE *f, long n) { long k; if (n >= 64) k = 4; else k = 3; print_mul_body(f, n, k, 0, 0, 0); print_mul_body(f, n, 4, 1, 0, 0); print_mul_body(f, n, 4, 2, 0, 0); print_mul_body(f, n, 4, 1, 0, 1); print_mul_body(f, n, 2, 0, 1, 0); print_alt_mul_body(f, n, k, 0, 0, 0); print_alt_mul_body(f, n, 4, 1, 0, 0); print_alt_mul_body(f, n, 4, 2, 0, 0); print_alt_mul_body(f, n, 4, 1, 0, 1); print_alt_mul_body(f, n, 2, 0, 1, 0); print_alt1_mul_body(f, n, k, 0, 0, 0); print_alt1_mul_body(f, n, 4, 1, 0, 0); print_alt1_mul_body(f, n, 4, 2, 0, 0); print_alt1_mul_body(f, n, 4, 1, 0, 1); print_alt1_mul_body(f, n, 2, 0, 1, 0); fprintf(f, "#define NTL_BB_MUL1_BITS (4)\n\n"); } void print_BB_sqr_code(FILE *f, long n) { long i, pos; fprintf(f, "\n\n"); fprintf(f, "#define NTL_BB_SQR_CODE \\\n"); fprintf(f, "lo=sqrtab[a&255];\\\n"); pos = 16; for (i = 8; i < n; i += 8) { if (2*(i+8) <= n) { fprintf(f, "lo=lo|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); pos += 16; } else if (2*i == n) { fprintf(f, "hi=sqrtab[(a>>%ld)&255];\\\n", i); pos = 16; } else if (2*i > n) { fprintf(f, "hi=hi|(sqrtab[(a>>%ld)&255]<<%ld);\\\n", i, pos); pos += 16; } else { /* only applies if word size is not a multiple of 16 */ fprintf(f, "_ntl_ulong t=sqrtab[(a>>%ld)&255];\\\n", i); fprintf(f, "lo=lo|(t<<%ld);\\\n", pos); fprintf(f, "hi=t>>%ld;\\\n", n-8); pos = 8; } } fprintf(f, "\n\n"); } void print_BB_rev_code(FILE *f, long n) { long i; fprintf(f, "\n\n"); fprintf(f, "#define NTL_BB_REV_CODE "); for (i = 0; i < n; i += 8) { if (i != 0) fprintf(f, "\\\n|"); fprintf(f, "(revtab[(a>>%ld)&255]<<%ld)", i, n-8-i); } fprintf(f, "\n\n"); } const char *yn_vec[2] = { "no", "yes" }; int main() { long bpl, bpi, bpt, rs_arith, nbits, wnbits; long nb_bpl; long dp, dr; long fma_detected; long reassoc_detected; long big_pointers; long ldp; FILE *f; long warnings = 0; unsigned long ulval; unsigned int uival; size_t tval; long slval; fprintf(stderr, "This is NTL version %s\n", NTL_VERSION); /* * compute bpl = bits per long */ ulval = val_ulong(1); bpl = 0; while (ulval) { ulval <<= 1; touch_ulong(&ulval); bpl++; } /* * compute nb_bpl = NumBits(bpl) */ ulval = bpl; nb_bpl = 0; while (ulval) { ulval = ulval >> 1; nb_bpl++; } /* * compute bpi = bits per int */ uival = val_uint(1); bpi = 0; while (uival) { uival <<= 1; touch_uint(&uival); bpi++; } /* * compute bpt = bits per size_t */ tval = val_size_t(1); bpt = 0; while (tval) { tval <<= 1; touch_size_t(&tval); bpt++; } /* * check if bpl and bpi are not too small --- any standard conforming * platform should pass this test. */ if (bpi < 16) { fprintf(stderr, "BAD NEWS: int type too short.\n"); return 1; } if (bpl < 32) { fprintf(stderr, "BAD NEWS: long type too short.\n"); return 1; } /* * check that there are 8 bits in a char. This is a POSIX requirement. */ if (CHAR_BIT != 8) { fprintf(stderr, "BAD NEWS: char type must have 8 bits.\n"); return 1; } /* * check that bpi is a multiple of 8. */ if (bpi % 8 != 0) { fprintf(stderr, "BAD NEWS: int type must be multiple of 8 bits.\n"); return 1; } /* * check that bpl is a multiple of 8. */ if (bpl % 8 != 0) { fprintf(stderr, "BAD NEWS: long type must be multiple of 8 bits.\n"); return 1; } /* * check if width of signed versions of int and long agree with that of * the unsigned versions, and that negative numbers are represented * using 2's compliment. * * The C99 standard, at least, is very precise about the possible * representations of unsigned and signed integer types, and so if * the following tests pass, we can be sure that the desired * properties hold. NTL relies implicitly and crucially on * these properties. * * I know of no machines for which these properties do not hold. */ if (((unsigned int) val_int(INT_MIN)) != val_uint(1U << (bpi-1))) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned int) val_int(INT_MAX)) != val_uint((1U << (bpi-1)) - 1U)) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned long) val_long(LONG_MIN)) != val_ulong(1UL << (bpl-1))) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } if (((unsigned long) val_long(LONG_MAX)) != val_ulong((1UL<<(bpl-1))-1UL)) { fprintf(stderr, "BAD NEWS: machine must be 2's compliment.\n"); return 1; } /* * check that floating point to integer conversions truncates toward zero * --- any standard conforming platform should pass this test. */ if (((long) val_double(1.75)) != 1L) { fprintf(stderr, "BAD NEWS: machine must truncate floating point toward zero.\n"); return 1; } if (((long) val_double(-1.75)) != -1L) { fprintf(stderr, "BAD NEWS: machine must truncate floating point toward zero.\n"); return 1; } /* * Test if right shift is arithemtic or not. According to the * standards, the result of right-shifting a negative number is * "implementation defined", which almost surely means the right shift * is *always* arithmetic or *always* logical. However, this cannot * be guaranteed, and so this test is *not* 100% portable --- but I * know of no machine for which this test does not correctly * predict the general behavior. One should set the NTL_CLEAN_INT * flag if one wants to avoid such machine dependencies. */ slval = val_long(-1); if ((slval >> 1) == slval) rs_arith = 1; else rs_arith = 0; /* * Next, we check some properties of floating point arithmetic. * An implementation should conform to the IEEE floating * point standard --- essentially all modern platforms do, * except for a few very old Cray's. There is no easy way * to check this, so we simply make a few simple sanity checks, * calculate the precision, and if the platform performs * double precision arithemtic in extended double precision registers. * The last property is one that the IEE standard allows, and which * some important platforms (like x86) have --- this is quite * unfortunate, as it really makes many of the other properties * of the IEEE standard unusable. */ /* * First, we simply check that we are using a machine with radix 2. */ if (FLT_RADIX != 2) { fprintf(stderr, "BAD NEWS: machine must use IEEE floating point.\n"); return 1; } /* * Next, we calculate the precision of "in memory" doubles, * and check that it is at least 53. */ dp = DoublePrecision(); if (dp < 53) { fprintf(stderr, "BAD NEWS: machine must use IEEE floating point (*).\n"); return 1; } /* * Next, we check that the *range* of doubles is sufficiently large. * Specifically, we require that DBL_MAX > 2^{7*max(bpl, dp)} * and 1/DBL_MIN > 2^{7*max(bpl, dp)}. * On IEEE floating point compliant machines, this * will hold, and the following test will pass, if bpl is at most 128, which * should be true for the foreseeable future. */ if (log(DBL_MAX)/log(2.0) < 7.01*bpl || log(DBL_MAX)/log(2.0) < 7.01*dp || -log(DBL_MIN)/log(2.0) < 7.01*bpl || -log(DBL_MIN)/log(2.0) < 7.01*dp) { fprintf(stderr, "BAD NEWS: range of doubles too small.\n"); return 1; } /* * Next, we check if the machine has wider "in-register" doubles or not. * This test almost always yields the correct result --- if not, * you will have to set the NTL_EXT_DOUBLE in "mach_desc.h" * by hand. */ dr = DoubleRounding(dp); /* * Next, we check if the platform uses FMA (fused multiply add), * even across statement boundaries. */ fma_detected = FMADetected(dp); /* * Next, we check if the platform may reassociate FP operations. */ reassoc_detected = ReassocDetected(dp); /* * Next, we test the precision of long doubles. * If long doubles don't look good or useful, ldp == 0. * Right now, we ony enable long double usage on Intel/gcc * platforms. */ ldp = LongDoublePrecision(); if (ldp <= dp || !GNUC_INTEL) ldp = 0; // Disable if it looks like rounding doesn't work right if (((long) val_ldouble(1.75)) != 1L) ldp = 0; if (((long) val_ldouble(-1.75)) != -1L) ldp = 0; if (reassoc_detected) { fprintf(stderr, "BAD NEWS: Floating point reassociation detected.\n"); fprintf(stderr, "Do not use -Ofast, -ffast-math.\n"); return 1; } /* * Set nbits = min(bpl-2, dp-3) [and even] * Given the minimum size of blp and dp, the smallest possible * value of nbits is 30. */ if (bpl-2 < dp-3) nbits = bpl-2; else nbits = dp-3; if (nbits % 2 != 0) nbits--; /* * Set wnbits = min(bpl-2, ldp-2) [and even] */ if (ldp) { if (bpl-2 < ldp-2) wnbits = bpl-2; else wnbits = ldp-2; if (wnbits % 2 != 0) wnbits--; } else { wnbits = nbits; } if (wnbits <= nbits) ldp = 0; // disable long doubles if it doesn't increase nbits... // (for example, on 32-bit machines) big_pointers = 0; if (sizeof(char*) > sizeof(long)) big_pointers = 1; /* * That's it! All tests have passed. */ fprintf(stderr, "\n*** GOOD NEWS: compatible machine.\n"); fprintf(stderr, "summary of machine characteristics:\n"); fprintf(stderr, "bits per long = %ld\n", bpl); fprintf(stderr, "bits per int = %ld\n", bpi); fprintf(stderr, "bits per size_t = %ld\n", bpt); fprintf(stderr, "arith right shift = %s\n", yn_vec[rs_arith]); fprintf(stderr, "double precision = %ld\n", dp); fprintf(stderr, "long double precision = %ld\n", ldp); fprintf(stderr, "NBITS (maximum) = %ld\n", nbits); fprintf(stderr, "WNBITS (maximum) = %ld\n", wnbits); fprintf(stderr, "double rounding detected = %s\n", yn_vec[dr]); fprintf(stderr, "FMA detected = %s\n", yn_vec[fma_detected]); fprintf(stderr, "big pointers = %s\n", yn_vec[big_pointers]); if (dr && GNUC_INTEL) fprintf(stderr, "-- auto x86 fix\n"); if (dp != 53) { warnings = 1; fprintf(stderr, "\n*** WARNING :\n"); fprintf(stderr, "Nonstandard floating point precision.\n"); fprintf(stderr, "IEEE standard is 53 bits.\n"); } #if (defined(__sparc__) && !defined(__sparc_v8__) && \ !defined(__sparcv8) && !defined(__sparc_v9__) && !defined(__sparcv9)) warnings = 1; fprintf(stderr, "\n*** WARNING :\n"); fprintf(stderr, "If this Sparc is a Sparc-10 or later (so it has\n"); fprintf(stderr, "a hardware integer multiply instruction) you\n"); fprintf(stderr, "should specify the -mv8 option in the makefile\n"); fprintf(stderr, "to obtain more efficient code.\n"); #endif if (dr && !GNUC_INTEL) { warnings = 1; fprintf(stderr, "\n*** WARNING :\n"); fprintf(stderr, "This platform has extended double precision registers.\n"); fprintf(stderr, "While that may sound like a good thing, it actually is not.\n"); fprintf(stderr, "If this is a Pentium or other x86 and your compiler\n"); fprintf(stderr, "is g++ or supports GNU 'asm' constructs, it is recommended\n"); fprintf(stderr, "to compile NTL with the NTL_X86_FIX flag to get true IEEE floating point.\n"); fprintf(stderr, "Set this flag by editing the file config.h.\n"); fprintf(stderr, "The code should still work even if you don't set\n"); fprintf(stderr, "this flag. See quad_float.txt for details.\n\n"); } #if 0 /* better not to be interactive */ if (warnings) { int c; fprintf(stderr, "Do you want to continue anyway[y/n]? "); c = getchar(); if (c == 'n' || c == 'N') { fprintf(stderr, "Make the necessary changes to the makefile and/or config.h,\n"); fprintf(stderr, "then type 'make clobber' and then 'make'.\n\n\n"); return 1; } } #else if (warnings) { fprintf(stderr, "\n\n"); fprintf(stderr, "********************************************************\n"); fprintf(stderr, "********************************************************\n"); fprintf(stderr, "**** !!! SEE WARNINGS ABOVE !!! ****\n"); fprintf(stderr, "********************************************************\n"); fprintf(stderr, "********************************************************\n"); fprintf(stderr, "\n\n"); } #endif f = fopen("mach_desc.h", "w"); if (!f) { fprintf(stderr, "can't open mach_desc.h for writing\n"); return 1; } fprintf(f, "#ifndef NTL_mach_desc__H\n"); fprintf(f, "#define NTL_mach_desc__H\n\n\n"); fprintf(f, "#define NTL_BITS_PER_LONG (%ld)\n", bpl); fprintf(f, "#define NTL_NUMBITS_BPL (%ld)\n", nb_bpl); fprintf(f, "#define NTL_MAX_LONG (%ldL)\n", ((long) ((1UL<<(bpl-1))-1UL))); fprintf(f, "#define NTL_MAX_INT (%ld)\n", ((long) ((1UL<<(bpi-1))-1UL))); fprintf(f, "#define NTL_BITS_PER_INT (%ld)\n", bpi); fprintf(f, "#define NTL_BITS_PER_SIZE_T (%ld)\n", bpt); fprintf(f, "#define NTL_ARITH_RIGHT_SHIFT (%ld)\n", rs_arith); fprintf(f, "#define NTL_NBITS_MAX (%ld)\n", nbits); fprintf(f, "#define NTL_WNBITS_MAX (%ld)\n", wnbits); fprintf(f, "#define NTL_DOUBLE_PRECISION (%ld)\n", dp); fprintf(f, "#define NTL_FDOUBLE_PRECISION "); print2k(f, dp-1, bpl); fprintf(f, "\n"); if (ldp) { fprintf(f, "#define NTL_LONGDOUBLE_OK (1)\n"); fprintf(f, "#define NTL_LONGDOUBLE_PRECISION (%ld)\n", ldp); fprintf(f, "#define NTL_WIDE_DOUBLE_LDP "); print2k_WD(f, ldp-1, bpl); fprintf(f, "\n"); fprintf(f, "#define NTL_WIDE_DOUBLE_DP "); print2k_WD(f, dp-1, bpl); fprintf(f, "\n"); } else { fprintf(f, "#define NTL_LONGDOUBLE_OK (0)\n"); fprintf(f, "#define NTL_WIDE_DOUBLE_DP "); print2k_WD(f, dp-1, bpl); fprintf(f, "\n"); } fprintf(f, "#define NTL_QUAD_FLOAT_SPLIT ("); print2k(f, dp - (dp/2), bpl); fprintf(f, "+1.0)\n"); fprintf(f, "#define NTL_EXT_DOUBLE (%ld)\n", dr); fprintf(f, "#define NTL_FMA_DETECTED (%ld)\n", fma_detected); fprintf(f, "#define NTL_BIG_POINTERS (%ld)\n", big_pointers); fprintf(f, "#define NTL_MIN_LONG (-NTL_MAX_LONG - 1L)\n"); fprintf(f, "#define NTL_MIN_INT (-NTL_MAX_INT - 1)\n"); print_BB_mul_code(f, bpl); print_BB_sqr_code(f, bpl); print_BB_rev_code(f, bpl); fprintf(f, "#endif\n\n"); fclose(f); fprintf(stderr, "\n\n"); return 0; } ntl-11.5.1/src/MakeDescAux.cpp0000644417616742025610000000226414064716022017606 0ustar gid-shoupvpug-gid-shoupv #include using namespace std; int val_int(int x) { return x; } unsigned int val_uint(unsigned int x) { return x; } long val_long(long x) { return x; } unsigned long val_ulong(unsigned long x) { return x; } size_t val_size_t(size_t x) { return x; } double val_double(double x) { return x; } long double val_ldouble(double x) { return x; } void touch_int(int* x) {} void touch_uint(unsigned int* x) {} void touch_long(long* x) {} void touch_ulong(unsigned long* x) {} void touch_size_t(size_t* x) {} void touch_double(double* x) {} void touch_ldouble(long double* x) {} double sum_double(double *x, long n) { long i; double acc = 0; for (i = 0; i < n; i++) acc += x[i]; return acc; } double fma_test(double a, double b, double c) { double t1 = a*b; double t2 = t1 + c; return t2; } double reassoc_test(double a, double b, double c, double d) { double t1 = a*c + a*d; double t2 = b*c + b*d; return t1 + t2; // an optimizing compiler that reassociates will almost // surely compute this as (a+b)*(c+d). } double power2(long k) { long i; double res; res = 1; for (i = 1; i <= k; i++) res = res * 2; return res; } ntl-11.5.1/src/newnames.cpp0000644417616742025610000001207614064716022017273 0ustar gid-shoupvpug-gid-shoupv /************************************************************************ This program can be compiled under either C or C++. It copies its input to its output, substituting all old NTL macro names by new NTL macro names. This is intended to automate the transition from NTL 3.1 to 3.5. Each maximal length alphanumeric substring in the input is looked up in a table, and if there is a match, the substring is replaced. *************************************************************************/ #include #include #define NumNames (79) const char *names[NumNames][2] = { { "BB_HALF_MUL_CODE", "NTL_BB_HALF_MUL_CODE" }, { "BB_MUL_CODE", "NTL_BB_MUL_CODE" }, { "BB_REV_CODE", "NTL_BB_REV_CODE" }, { "BB_SQR_CODE", "NTL_BB_SQR_CODE" }, { "FFTFudge", "NTL_FFTFudge" }, { "FFTMaxRoot", "NTL_FFTMaxRoot" }, { "FFTMaxRootBnd", "NTL_FFTMaxRootBnd" }, { "QUAD_FLOAT_SPLIT", "NTL_QUAD_FLOAT_SPLIT" }, { "WV_NTL_RANGE_CHECK_CODE", "NTL_WV_RANGE_CHECK_CODE" }, { "WordVectorExpansionRatio", "NTL_WordVectorExpansionRatio" }, { "WordVectorInputBlock", "NTL_WordVectorInputBlock" }, { "WordVectorMinAlloc", "NTL_WordVectorMinAlloc" }, { "XD_BOUND", "NTL_XD_BOUND" }, { "XD_BOUND_INV", "NTL_XD_BOUND_INV" }, { "XD_HBOUND", "NTL_XD_HBOUND" }, { "XD_HBOUND_INV", "NTL_XD_HBOUND_INV" }, { "ZZ_ARITH_RIGHT_SHIFT", "NTL_ARITH_RIGHT_SHIFT" }, { "ZZ_BITS_PER_INT", "NTL_BITS_PER_INT" }, { "ZZ_BITS_PER_LONG", "NTL_BITS_PER_LONG" }, { "ZZ_DOUBLES_LOW_HIGH", "NTL_DOUBLES_LOW_HIGH" }, { "ZZ_DOUBLE_PRECISION", "NTL_DOUBLE_PRECISION" }, { "ZZ_EXT_DOUBLE", "NTL_EXT_DOUBLE" }, { "ZZ_FDOUBLE_PRECISION", "NTL_FDOUBLE_PRECISION" }, { "ZZ_FRADIX", "NTL_FRADIX" }, { "ZZ_FRADIX_INV", "NTL_FRADIX_INV" }, { "ZZ_FetchHiLo", "NTL_FetchHiLo" }, { "ZZ_FetchLo", "NTL_FetchLo" }, { "ZZ_HI_WD", "NTL_HI_WD" }, { "ZZ_LO_WD", "NTL_LO_WD" }, { "ZZ_MAX_INT", "NTL_MAX_INT" }, { "ZZ_MAX_LONG", "NTL_MAX_LONG" }, { "ZZ_MIN_INT", "NTL_MIN_INT" }, { "ZZ_MIN_LONG", "NTL_MIN_LONG" }, { "ZZ_NBITS", "NTL_NBITS" }, { "ZZ_NBITSH", "NTL_NBITSH" }, { "ZZ_NBITS_MAX", "NTL_NBITS_MAX" }, { "ZZ_NTL_SINGLE_MUL_OK", "NTL_SINGLE_MUL_OK" }, { "ZZ_PRIME_BND", "NTL_PRIME_BND" }, { "ZZ_RADIX", "NTL_RADIX" }, { "ZZ_RADIXM", "NTL_RADIXM" }, { "ZZ_RADIXROOT", "NTL_RADIXROOT" }, { "ZZ_RADIXROOTM", "NTL_RADIXROOTM" }, { "ZZ_pRegister", "NTL_ZZ_pRegister" }, { "ZZ_pX_BERMASS_CROSSOVER", "NTL_ZZ_pX_BERMASS_CROSSOVER" }, { "ZZ_pX_DIV_CROSSOVER", "NTL_ZZ_pX_DIV_CROSSOVER" }, { "ZZ_pX_FFT_CROSSOVER", "NTL_ZZ_pX_FFT_CROSSOVER" }, { "ZZ_pX_GCD_CROSSOVER", "NTL_ZZ_pX_GCD_CROSSOVER" }, { "ZZ_pX_HalfGCD_CROSSOVER", "NTL_ZZ_pX_HalfGCD_CROSSOVER" }, { "ZZ_pX_NEWTON_CROSSOVER", "NTL_ZZ_pX_NEWTON_CROSSOVER" }, { "ZZ_pX_TRACE_CROSSOVER", "NTL_ZZ_pX_TRACE_CROSSOVER" }, { "ntl_eq_matrix_decl", "NTL_eq_matrix_decl" }, { "ntl_eq_matrix_impl", "NTL_eq_matrix_impl" }, { "ntl_eq_vector_decl", "NTL_eq_vector_decl" }, { "ntl_eq_vector_impl", "NTL_eq_vector_impl" }, { "ntl_io_matrix_decl", "NTL_io_matrix_decl" }, { "ntl_io_matrix_impl", "NTL_io_matrix_impl" }, { "ntl_io_vector_decl", "NTL_io_vector_decl" }, { "ntl_io_vector_impl", "NTL_io_vector_impl" }, { "ntl_matrix_decl", "NTL_matrix_decl" }, { "ntl_matrix_impl", "NTL_matrix_impl" }, { "ntl_pair_decl", "NTL_pair_decl" }, { "ntl_pair_eq_decl", "NTL_pair_eq_decl" }, { "ntl_pair_eq_impl", "NTL_pair_eq_impl" }, { "ntl_pair_impl", "NTL_pair_impl" }, { "ntl_pair_io_decl", "NTL_pair_io_decl" }, { "ntl_pair_io_impl", "NTL_pair_io_impl" }, { "ntl_vector_decl", "NTL_vector_decl" }, { "ntl_vector_default", "NTL_vector_default" }, { "ntl_vector_impl", "NTL_vector_impl" }, { "ntl_vector_impl_plain", "NTL_vector_impl_plain" }, { "zz_pRegister", "NTL_zz_pRegister" }, { "zz_pX_BERMASS_CROSSOVER", "NTL_zz_pX_BERMASS_CROSSOVER" }, { "zz_pX_DIV_CROSSOVER", "NTL_zz_pX_DIV_CROSSOVER" }, { "zz_pX_GCD_CROSSOVER", "NTL_zz_pX_GCD_CROSSOVER" }, { "zz_pX_HalfGCD_CROSSOVER", "NTL_zz_pX_HalfGCD_CROSSOVER" }, { "zz_pX_MOD_CROSSOVER", "NTL_zz_pX_MOD_CROSSOVER" }, { "zz_pX_MUL_CROSSOVER", "NTL_zz_pX_MUL_CROSSOVER" }, { "zz_pX_NEWTON_CROSSOVER", "NTL_zz_pX_NEWTON_CROSSOVER" }, { "zz_pX_TRACE_CROSSOVER", "NTL_zz_pX_TRACE_CROSSOVER" }, }; void PrintName(const char *name) { int i; i = 0; while (i < NumNames && strcmp(name, names[i][0])) i++; if (i >= NumNames) printf("%s", name); else printf("%s", names[i][1]); } int IsAlphaNum(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9')); } char buf[10000]; int main() { int c; int state; int len; state = 0; len = 0; do { c = getchar(); switch (state) { case 0: if (IsAlphaNum(c)) { buf[len] = c; len++; state = 1; } else { if (c != EOF) putchar(c); } break; case 1: if (IsAlphaNum(c)) { buf[len] = c; len++; } else { buf[len] = '\0'; PrintName(buf); len = 0; if (c != EOF) putchar(c); state = 0; } break; } } while (c != EOF); return 0; } ntl-11.5.1/src/gen_gmp_aux.cpp0000644417616742025610000000657514064716022017756 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include using namespace std; #ifndef NTL_GMP_LIP int main() { fprintf(stderr, "NTL_GMP_LIP flag not set\n"); return 0; } #else #include #include void print2k(FILE *f, long k, long bpl) { long m, l; long first; if (k <= 0) { fprintf(f, "((double) 1.0)"); return; } m = bpl - 2; first = 1; fprintf(f, "("); while (k > 0) { if (k > m) l = m; else l = k; k = k - l; if (first) first = 0; else fprintf(f, "*"); fprintf(f, "((double)(1L<<%ld))", l); } fprintf(f, ")"); } void Error(const char *s) { fprintf(stderr, "*** %s\n", s); abort(); } char buffer[1024]; int main() { long bpl; long ntl_zz_nbits; long nail_bits; fprintf(stderr, "NTL_GMP_LIP flag set\n"); bpl = NTL_BITS_PER_LONG; /* * We require that the number of bits per limb quantity correspond to the * number of bits of a long, or possibly a "long long" that is twice as wide * as a long. These restrictions will almost certainly be satisfied. */ ntl_zz_nbits = 0; nail_bits = 0; #ifdef GMP_NAIL_BITS nail_bits = GMP_NAIL_BITS; #endif if (nail_bits > 0) fprintf(stderr, "WARNING: GMP_NAIL_BITS > 0: this has not been well tested\n"); if (__GNU_MP_VERSION < 5) Error("GMP version 5.0.0 or later required"); // check that GMP_LIMB_BITS == mp_bits_per_limb as a consistency check if (GMP_LIMB_BITS != mp_bits_per_limb) Error("GMP_LIMB_BITS != mp_bits_per_limb: inconsistency between gmp.h and libgmp"); // check that vesrion numbers match as a consistency check // This is adapted from MPFR's configure script bool bad_version = false; sprintf(buffer, "%d.%d.%d", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL); fprintf(stderr, "GMP version check (%s/%s)\n", buffer, gmp_version); if (strcmp(buffer, gmp_version)) { if (__GNU_MP_VERSION_PATCHLEVEL != 0) bad_version = true; else { sprintf(buffer, "%d.%d", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR); if (strcmp(buffer, gmp_version)) bad_version = true; } } if (bad_version) Error("version number mismatch: inconsistency between gmp.h and libgmp"); if (sizeof(mp_limb_t) == sizeof(long) && mp_bits_per_limb == bpl) ntl_zz_nbits = bpl-nail_bits; else if (sizeof(mp_limb_t) == 2*sizeof(long) && mp_bits_per_limb == 2*bpl) ntl_zz_nbits = 2*bpl-nail_bits; else Error("sorry...this is a funny gmp"); if (ntl_zz_nbits % 2 != 0 || ntl_zz_nbits < 30) Error("sorry...this is a funny gmp"); if (sizeof(mp_size_t) != sizeof(long) && sizeof(mp_size_t) != sizeof(int)) Error("sorry...this is a funny gmp"); if (sizeof(mp_size_t) < sizeof(long)) { printf("#define NTL_SMALL_MP_SIZE_T\n"); fprintf(stderr, "setting NTL_SMALL_MP_SIZE_T\n"); } fprintf(stderr, "NTL_ZZ_NBITS = %ld\n", ntl_zz_nbits); printf("#define NTL_ZZ_NBITS (%ld)\n", ntl_zz_nbits); fprintf(stderr, "NTL_BITS_PER_LIMB_T = %ld\n", ntl_zz_nbits+nail_bits); printf("#define NTL_BITS_PER_LIMB_T (%ld)\n", ntl_zz_nbits+nail_bits); printf("#define NTL_ZZ_FRADIX "); print2k(stdout, ntl_zz_nbits, bpl); printf("\n"); return 0; } #endif ntl-11.5.1/src/gf2x_version_1_2_or_later_required.cpp0000644417616742025610000000111514064716022024311 0ustar gid-shoupvpug-gid-shoupv#include #if (defined(NTL_GF2X_LIB) && defined(NTL_THREADS)) // we require v1.2 or later #include #ifndef GF2X_VERSION_MAJOR // versions after v1.2 should define GF2X_VERSION_MAJOR extern "C" { struct gf2x_ternary_fft_info_s; typedef const struct gf2x_ternary_fft_info_s * gf2x_ternary_fft_info_srcptr; int gf2x_ternary_fft_compatible(gf2x_ternary_fft_info_srcptr o1, gf2x_ternary_fft_info_srcptr o2); } // This will fail to link for versions prior to v1.2. void fun() { gf2x_ternary_fft_compatible(0, 0); } #endif #endif int main() { return 0; } ntl-11.5.1/src/GetTime0.cpp0000644417616742025610000000766114064716022017100 0ustar gid-shoupvpug-gid-shoupv /* * Author: David Robert Nadeau * Site: http://NadeauSoftware.com/ * License: Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/deed.en_US */ // NTL NOTES: I've adapted this code from the above source. // The reason is that for some multithreaded benchmarking, I want // to use wall clock time, and this seemed like the best multiplatform // solution to getting a high-resolution wall clock timer. // The only change I made to the original code is to initialize // timeConvert for the OSX case using a thread-safe initialization // C++ idiom. #if defined(_WIN32) #include #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) #include /* POSIX flags */ #include /* clock_gettime(), time() */ #include /* gethrtime(), gettimeofday() */ #if defined(__MACH__) && defined(__APPLE__) #include #include static inline double InitTimeConvert() { mach_timebase_info_data_t timeBase; (void)mach_timebase_info( &timeBase ); return (double)timeBase.numer / (double)timeBase.denom / 1000000000.0; } #endif #else #error "Unable to define GetTime( ) for an unknown OS." #endif /** * Returns the real time, in seconds, or -1.0 if an error occurred. * * Time is measured since an arbitrary and OS-dependent start time. * The returned real time is only useful for computing an elapsed time * between two calls to this function. */ double _ntl_GetTime( ) { #if defined(_WIN32) FILETIME tm; ULONGLONG t; #if defined(NTDDI_WIN8) && NTDDI_VERSION >= NTDDI_WIN8 /* Windows 8, Windows Server 2012 and later. ---------------- */ GetSystemTimePreciseAsFileTime( &tm ); #else /* Windows 2000 and later. ---------------------------------- */ GetSystemTimeAsFileTime( &tm ); #endif t = ((ULONGLONG)tm.dwHighDateTime << 32) | (ULONGLONG)tm.dwLowDateTime; return (double)t / 10000000.0; #elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) /* HP-UX, Solaris. ------------------------------------------ */ return (double)gethrtime( ) / 1000000000.0; #elif defined(__MACH__) && defined(__APPLE__) /* OSX. ----------------------------------------------------- */ static double timeConvert = InitTimeConvert(); // even in a multi-threaded environment, this will // be safely initialized, according to C++11 standard return (double)mach_absolute_time( ) * timeConvert; #elif defined(_POSIX_VERSION) /* POSIX. --------------------------------------------------- */ #if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) { struct timespec ts; #if defined(CLOCK_MONOTONIC_PRECISE) /* BSD. --------------------------------------------- */ const clockid_t id = CLOCK_MONOTONIC_PRECISE; #elif defined(CLOCK_MONOTONIC_RAW) /* Linux. ------------------------------------------- */ const clockid_t id = CLOCK_MONOTONIC_RAW; #elif defined(CLOCK_HIGHRES) /* Solaris. ----------------------------------------- */ const clockid_t id = CLOCK_HIGHRES; #elif defined(CLOCK_MONOTONIC) /* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ const clockid_t id = CLOCK_MONOTONIC; #elif defined(CLOCK_REALTIME) /* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ const clockid_t id = CLOCK_REALTIME; #else const clockid_t id = (clockid_t)-1; /* Unknown. */ #endif /* CLOCK_* */ if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; /* Fall thru. */ } #endif /* _POSIX_TIMERS */ /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ struct timeval tm; gettimeofday( &tm, NULL ); return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; #else return -1.0; /* Failed. */ #endif } ntl-11.5.1/src/GetTime1.cpp0000644417616742025610000000061414064716022017070 0ustar gid-shoupvpug-gid-shoupv#include #include // FIXME: it would be nice to have a per-thread // timing function, but it seems very difficult // to get a cross-platform solution to this. double _ntl_GetTime() { struct rusage used; getrusage(RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-11.5.1/src/GetTime2.cpp0000644417616742025610000000057414064716022017076 0ustar gid-shoupvpug-gid-shoupv#include #include // some (old?) Solaris systems don't seem // to supply a getrusage prototype extern "C" int getrusage(int, struct rusage*); double _ntl_GetTime() { struct rusage used; getrusage(RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-11.5.1/src/GetTime3.cpp0000644417616742025610000000044114064716022017070 0ustar gid-shoupvpug-gid-shoupv#include #include #include double _ntl_GetTime() { struct rusage used; syscall(SYS_getrusage, RUSAGE_SELF, &used); return (used.ru_utime.tv_sec + used.ru_stime.tv_sec + (used.ru_utime.tv_usec + used.ru_stime.tv_usec) / 1e6); } ntl-11.5.1/src/GetTime4.cpp0000644417616742025610000000123114064716022017067 0ustar gid-shoupvpug-gid-shoupv#include using namespace std; // FIXME: this is the GetTime that ends up getting used // on Windows. However, it returns the wall time, not CPU time. // We could perhaps switch to using GetProcessTimes. // See: http://nadeausoftware.com/articles/2012/03/c_c_tip_how_measure_cpu_time_benchmarking // NOTE: on Windows, CLOCKS_PER_SEC is 1000 and clock_t is a 32 bit integer, // this can go for almost 600 hours without overflowing. // NOTE: on Windows, clock does not necessarily wrap-around, // but instead may return -1 after an overflow. double _ntl_GetTime() { clock_t this_clock = clock(); return double(this_clock)/double(CLOCKS_PER_SEC); } ntl-11.5.1/src/GetTime5.cpp0000644417616742025610000000010114064716022017063 0ustar gid-shoupvpug-gid-shoupv#include double _ntl_GetTime() { return 0; } ntl-11.5.1/src/TestGetTime.cpp0000644417616742025610000000207014064716022017645 0ustar gid-shoupvpug-gid-shoupv#include #include using namespace std; double _ntl_GetTime(); /* Assuming the processor speed is at most 200GHz, and that * the clock resolution is at least 1 millisecond, the following * code should correctly determine if the GetTime function * is working properly, and should not run for more than * a few seconds on a machine with a speed of at least 100MHz. */ #define LOOP_COUNT (400) int main(int argc, char **argv) { long a, x, n, m; long i, j, k; double t0, t1; fprintf(stderr, "running"); x = atol(argv[1]); /* = 1 */ n = atol(argv[2]); /* = 1048576 = 2^20 */ m = atol(argv[3]); /* = 1048575 = 2^20 - 1 */ k = -1; t0 = _ntl_GetTime(); a = 1; for (i = 1; i <= LOOP_COUNT; i++) { for (j = 0; j < n; j++) a = (a + x) & m; if (a == 17) return -2; /* keeps the compiler honest! */ t1 = _ntl_GetTime(); if (t1 > t0) { fprintf(stderr, "\n"); return 0; } if ((i % 10) == 0) { fprintf(stderr, "."); } } fprintf(stderr, "\n"); return -1; } ntl-11.5.1/src/GetPID1.cpp0000644417616742025610000000014214064716022016602 0ustar gid-shoupvpug-gid-shoupv #include #include unsigned long _ntl_GetPID() { return getpid(); } ntl-11.5.1/src/GetPID2.cpp0000644417616742025610000000005714064716022016610 0ustar gid-shoupvpug-gid-shoupv unsigned long _ntl_GetPID() { return 0; } ntl-11.5.1/src/TestGetPID.cpp0000644417616742025610000000026514064716022017367 0ustar gid-shoupvpug-gid-shoupv #include #include #include using namespace std; unsigned long _ntl_GetPID(); int main() { printf("%lu\n", _ntl_GetPID()); return 0; } ntl-11.5.1/src/CheckCompile.cpp0000644417616742025610000000003214064716022017771 0ustar gid-shoupvpug-gid-shoupv int main() { return 0; } ntl-11.5.1/src/GenConfigInfo.cpp0000644417616742025610000000304714064716022020127 0ustar gid-shoupvpug-gid-shoupv#include /* output (compiler_name,language_standard,cpu_type) compiler_name: Right now, we just recognize "gcc", "clang", and "icc". Other compilers are named "unknown". language_standard: As of 2018, the available language standards are 199711, 201103, 201402, 201703. cpu_type: Right now, we just recognize x86 and x86-64, and both are named "x86". Other CPUs are named "unknown". */ #ifndef __cplusplus #define __cplusplus 1 #endif int main() { long language_standard = __cplusplus; // convert to one of 0, 1997, 2011, 2014, 2017 if (language_standard >= 201703) language_standard = 2017; else if (language_standard >= 201402) language_standard = 2014; else if (language_standard >= 201103) language_standard = 2011; else if (language_standard >= 199711) language_standard = 1997; else language_standard = 0; const char *compiler_name = "unknown"; const char *cpu_type = "unknown"; const char *os_name = "unknown"; #if defined(__INTEL_COMPILER) compiler_name = "icc"; #elif defined(__clang__) compiler_name = "clang"; #elif defined (__GNUC__) compiler_name = "gcc"; #else compiler_name = ""; #endif #if defined(__x86_64__) || defined(__x86_64) || defined(__i386__) || defined(__i386) cpu_type = "x86"; #elif defined(__s390x__) cpu_type = "s390x"; #endif #if defined(__linux__) os_name = "linux"; #endif std::cout << "(" << compiler_name << "," << language_standard << "," << cpu_type << "," << os_name << ")\n"; } ntl-11.5.1/src/CheckContract.cpp0000644417616742025610000000145514064716022020170 0ustar gid-shoupvpug-gid-shoupv void touch_double(double* x); double val_double(double x); double power2(long k); double fma_test(double a, double b, double c); long FMADetected(long dp) { double x = power2(0) + power2(dp-1); double y = power2(0) + power2(dp-1); touch_double(&x); touch_double(&y); double z = x*y; touch_double(&z); z = -z; touch_double(&z); double lo = fma_test(x, y, z); return lo != 0; } long DoublePrecision() { double eps, one, res; long k; one = val_double(1.0); eps = val_double(1.0); k = 0; do { double tmp; k++; eps *= 1.0/2.0; tmp = 1.0 + eps; touch_double(&tmp); res = tmp - one; } while (res == eps); return k; } int main() { long dp = DoublePrecision(); long fma = FMADetected(dp); return int(fma); } ntl-11.5.1/src/CheckContractAux.cpp0000644417616742025610000000057114064716022020644 0ustar gid-shoupvpug-gid-shoupv#ifdef NTL_FP_CONTRACT_OFF #pragma fp_contract(off) #endif void touch_double(double* x) {} double val_double(double x) { return x; } double power2(long k) { long i; double res; res = 1; for (i = 1; i <= k; i++) res = res * 2; return res; } double fma_test(double a, double b, double c) { double t1 = a*b; double t2 = t1 + c; return t2; } ntl-11.5.1/src/CheckThreads.cpp0000644417616742025610000001134014064716022017777 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #include #include #include void TerminalError(const char *s) { std::cerr << s << "\n"; std::abort(); } void MemoryError() { TerminalError("out of memory"); } void ResourceError(const char *msg) { TerminalError(msg); } #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK)) #include #endif #define NTL_THREAD_LOCAL thread_local #ifdef __GNUC__ #define NTL_CHEAP_THREAD_LOCAL __thread #else #define NTL_CHEAP_THREAD_LOCAL thread_local #endif #define NTL_DETAILS_PTHREAD details_pthread #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK)) namespace details_pthread { struct Node { Node *next; Node() : next(0) { } virtual ~Node() { } }; template struct DerivedNode : Node { T t; template DerivedNode(Args&&... args) : t(std::forward(args)...) { } }; inline void delete_node(Node *p) noexcept { delete p; } // an exception here would likely lead to a complete mess... // the noexcept specification should force an immediate termination inline void delete_list(void *vp) { Node *p = (Node *) vp; while (p) { Node *tmp = p; p = p->next; delete_node(tmp); } } using namespace std; // I'm not sure if pthread stuff might be placed in namespace std struct key_wrapper { pthread_key_t key; key_wrapper(void (*destructor)(void*)) { if (pthread_key_create(&key, destructor)) ResourceError("pthread_key_create failed"); } }; inline void push_node(Node *p) // this pushes a new node to the front to the list // of objects that need to be deleted { if (!p) MemoryError(); static key_wrapper wkey(delete_list); // This relies on C++11 thread-safe static initialization. // It also relies on the guarantee that there is just one // global key (this requirement is only needed to // limit the number of keys, not for correctness). p->next = (Node *) pthread_getspecific(wkey.key); if (pthread_setspecific(wkey.key, p)) { delete_node(p); ResourceError("pthread_setspecific failed"); } } } #define NTL_TLS_LOCAL_INIT(type, var, init) \ static NTL_CHEAP_THREAD_LOCAL NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr_ ## var = 0; \ NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr_ ## var; \ if (!_ntl_hidden_variable_tls_local_ptr1_ ## var) { \ NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr2_ ## var = NTL_NEW_OP NTL_DETAILS_PTHREAD::DerivedNode init; \ NTL_DETAILS_PTHREAD::push_node(_ntl_hidden_variable_tls_local_ptr2_ ## var); \ _ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr2_ ## var; \ _ntl_hidden_variable_tls_local_ptr_ ## var = _ntl_hidden_variable_tls_local_ptr1_ ## var; \ } \ type &var = _ntl_hidden_variable_tls_local_ptr1_ ## var->t \ #else // NOTE: this definition of NTL_TLS_LOCAL_INIT ensures that var names // a local reference, regardless of the implementation #define NTL_TLS_LOCAL_INIT(type,var,init) \ static NTL_THREAD_LOCAL type _ntl_hidden_variable_tls_local ## var init; \ type &var = _ntl_hidden_variable_tls_local ## var #endif #define NTL_EMPTY_ARG #define NTL_TLS_LOCAL(type,var) NTL_TLS_LOCAL_INIT(type,var,NTL_EMPTY_ARG) #define NTL_TLS_GLOBAL_DECL_INIT(type,var,init) \ typedef type _ntl_hidden_typedef_tls_access_ ## var; \ static inline \ type& _ntl_hidden_function_tls_access_ ## var() { \ NTL_TLS_LOCAL_INIT(type,var,init); \ return var; \ } \ #define NTL_TLS_GLOBAL_DECL(type,var) NTL_TLS_GLOBAL_DECL_INIT(type,var,NTL_EMPTY_ARG) #define NTL_TLS_GLOBAL_ACCESS(var) \ _ntl_hidden_typedef_tls_access_ ## var & var = _ntl_hidden_function_tls_access_ ## var() //======================= std::atomic_long count_con(0); std::atomic_long count_des(0); std::atomic_long count1(0); struct X { long d; X() { d = count1++; count_con++; } ~X() { count_des++; } }; NTL_TLS_GLOBAL_DECL(X,x) void task(long *v) { NTL_TLS_GLOBAL_ACCESS(x); *v = x.d; } #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) int main() { long v1, v2, v3; std::thread t1(task, &v1); std::thread t2(task, &v2); std::thread t3(task, &v3); t1.join(); t2.join(); t3.join(); //std::cout << count_con << "\n"; //std::cout << count_des << "\n"; //std::cout << v1 << " " << v2 << " " << v3 << "\n"; long s1, s2, s3; s1 = MIN(MIN(v1,v2),v3); s3 = MAX(MAX(v1,v2),v3); s2 = v1+v2+v3-s1-s3; if (count_con != 3 || count_des != 3 || s1 != 0 || s2 != 1 || s3 != 2) { return -1; } return 0; } ntl-11.5.1/src/QuickTest.cpp0000644417616742025610000001607614064716022017376 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include NTL_CLIENT #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int SmallModulusTest(long p, long n) { zz_pBak bak; bak.save(); zz_p::init(p); zz_pX a, b, c, cc; random(a, n); random(b, n); PlainMul(c, a, b); FFTMul(cc, a, b); int res; res = (c != cc); bak.restore(); return res; } int GF2X_test() { GF2X a, b, c, c1; long n; #ifdef NTL_GF2X_LIB for (n = 32; n <= (1L << 18); n = n << 1) { random(a, n); random(b, n); OldMul(c, a, b); mul(c1, a, b); if (c1 != c) return 1; } #endif return 0; } void GF2X_time() { long iter; GF2X a, b, c; double t; long i; for (long n = 1000; n <= 1000000L; n *= 1000) { random(a, n); random(b, n); mul(c, a, b); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) mul(c, a, b); t = GetTime() - t; } while (t < 0.5); cerr << "time to multiply polynomials over GF(2) \n of degree < " << n << " : " << (t/iter) << "s"; #ifdef NTL_GF2X_LIB OldMul(c, a, b); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldMul(c, a, b); t = GetTime() - t; } while (t < 0.5); cerr << " [old code: " << (t/iter) << "s]"; #endif cerr << "\n"; } } #if 0 ZZX KarMul(const ZZX& a, const ZZX& b) { ZZX res; KarMul(res, a, b); return res; } #endif int main() { SetSeed(ZZ(0)); cerr << "This is NTL version " << NTL_VERSION << "\n"; cerr << "Hardware charactersitics:\n"; cerr << "NTL_BITS_PER_LONG = " << NTL_BITS_PER_LONG << "\n"; cerr << "NTL_ZZ_NBITS = " << NTL_ZZ_NBITS << "\n"; cerr << "NTL_SP_NBITS = " << NTL_SP_NBITS << "\n"; #ifdef NTL_LONGDOUBLE_SP_MULMOD cerr << "NTL_LONGDOUBLE_SP_MULMOD\n"; #endif #ifdef NTL_LONGLONG_SP_MULMOD cerr << "NTL_LONGLONG_SP_MULMOD\n"; #endif #include cerr << "\n"; cerr << "Basic Configuration Options:\n"; #ifdef NTL_LEGACY_NO_NAMESPACE cerr << "NTL_LEGACY_NO_NAMESPACE\n"; #endif #ifdef NTL_LEGACY_INPUT_ERROR cerr << "NTL_LEGACY_INPUT_ERROR\n"; #endif #ifdef NTL_THREADS cerr << "NTL_THREADS\n"; #endif #ifdef NTL_TLS_HACK cerr << "NTL_TLS_HACK\n"; #endif #ifdef NTL_EXCEPTIONS cerr << "NTL_EXCEPTIONS\n"; #endif #ifdef NTL_THREAD_BOOST cerr << "NTL_THREAD_BOOST\n"; #endif #ifdef NTL_LEGACY_SP_MULMOD cerr << "NTL_LEGACY_SP_MULMOD\n"; #endif #ifdef NTL_DISABLE_LONGDOUBLE cerr << "NTL_DISABLE_LONGDOUBLE\n"; #endif #ifdef NTL_DISABLE_LONGLONG cerr << "NTL_DISABLE_LONGLONG\n"; #endif #ifdef NTL_DISABLE_LL_ASM cerr << "NTL_DISABLE_LL_ASM\n"; #endif #ifdef NTL_MAXIMIZE_SP_NBITS cerr << "NTL_MAXIMIZE_SP_NBITS\n"; #endif #ifdef NTL_GMP_LIP cerr << "NTL_GMP_LIP\n"; #endif #ifdef NTL_GF2X_LIB cerr << "NTL_GF2X_LIB\n"; #endif #ifdef NTL_STD_CXX11 cerr << "NTL_STD_CXX11\n"; #endif #ifdef NTL_STD_CXX14 cerr << "NTL_STD_CXX14\n"; #endif #ifdef NTL_DISABLE_MOVE_ASSIGN cout << "NTL_DISABLE_MOVE_ASSIGN\n"; #endif #ifdef NTL_DISABLE_MOVE cout << "NTL_DISABLE_MOVE\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cerr << "NTL_UNSIGNED_LONG_LONG_TYPE: "; cerr << make_string(NTL_UNSIGNED_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_X86_FIX cerr << "NTL_X86_FIX\n"; #endif #ifdef NTL_NO_X86_FIX cerr << "NTL_NO_X86_FIX\n"; #endif #ifdef NTL_NO_INIT_TRANS cerr << "NTL_NO_INIT_TRANS\n"; #endif #ifdef NTL_CLEAN_INT cerr << "NTL_CLEAN_INT\n"; #endif #ifdef NTL_CLEAN_PTR cerr << "NTL_CLEAN_PTR\n"; #endif #ifdef NTL_SAFE_VECTORS cerr << "NTL_SAFE_VECTORS\n"; #endif #ifdef NTL_ENABLE_AVX_FFT cerr << "NTL_ENABLE_AVX_FFT\n"; #endif #ifdef NTL_AVOID_AVX512 cerr << "NTL_AVOID_AVX512\n"; #endif #ifdef NTL_RANGE_CHECK cerr << "NTL_RANGE_CHECK\n"; #endif cerr << "\n"; cerr << "Resolution of double-word type:\n"; cerr << make_string(NTL_ULL_TYPE) << "\n"; cerr << "\n"; cerr << "Performance Options:\n"; #ifdef NTL_SPMM_ULL cerr << "NTL_SPMM_ULL\n"; #endif #ifdef NTL_AVOID_BRANCHING cerr << "NTL_AVOID_BRANCHING\n"; #endif #ifdef NTL_FFT_BIGTAB cerr << "NTL_FFT_BIGTAB\n"; #endif #ifdef NTL_FFT_LAZYMUL cerr << "NTL_FFT_LAZYMUL\n"; #endif #ifdef NTL_TBL_REM cerr << "NTL_TBL_REM\n"; #endif #ifdef NTL_CRT_ALTCODE cerr << "NTL_CRT_ALTCODE\n"; #endif #ifdef NTL_CRT_ALTCODE_SMALL cerr << "NTL_CRT_ALTCODE_SMALL\n"; #endif #ifdef NTL_GF2X_ALTCODE cerr << "NTL_GF2X_ALTCODE\n"; #endif #ifdef NTL_GF2X_ALTCODE1 cerr << "NTL_GF2X_ALTCODE1\n"; #endif #ifdef NTL_GF2X_NOINLINE cerr << "NTL_GF2X_NOINLINE\n"; #endif cerr << "\n\n"; cerr << "running tests"; long n, k, i; n = 250; k = 16000; ZZ p; for (i = 0; i < 15; i++) { //cerr << "(" << n << "," << k << ")"; cerr << "."; RandomLen(p, k); ZZ_p::init(p); ZZ_pX a, b, c, c1; random(a, n); random(b, n); FFTMul(c, a, b); //cerr << ZZ_pInfo->FFTInfo->NumPrimes; KarMul(c1, a, b); //c1 = conv( KarMul( conv(a), conv(b) ) ); if (c1 != c) { cerr << "ZZ_pX mul failed!\n"; return 1; } n = long(n * 1.35); k = long(k / 1.414); } // small prime tests...I've made some changes in v5.3 // that should be checked on various platforms, so // we might as well check them here. if (SmallModulusTest(17, 1000)) { cerr << "first SmallModulusTest failed!!\n"; return 1; } if (SmallModulusTest((1L << (NTL_SP_NBITS))-1, 1000)) { cerr << "second SmallModulusTest failed!!\n"; return 1; } // Test gf2x code.... if (GF2X_test()) { cerr << "GF2X test failed!\n"; return 1; } cerr << "OK\n"; ZZ x1, x2, x3, x4; double t; RandomLen(x1, 1024); RandomBnd(x2, x1); RandomBnd(x3, x1); mul(x4, x2, x3); t = GetTime(); for (i = 0; i < 100000; i++) mul(x4, x2, x3); t = GetTime()-t; cerr << "time for 1024-bit mul: " << t*10 << "us"; cerr << "\n"; rem(x2, x4, x1); t = GetTime(); for (i = 0; i < 100000; i++) rem(x2, x4, x1); t = GetTime()-t; cerr << "time for 2048/1024-bit rem: " << t*10 << "us"; cerr << "\n"; GenPrime(p, 1024); RandomBnd(x1, p); if (IsZero(x1)) set(x1); InvMod(x2, x1, p); t = GetTime(); for (i = 0; i < 1000; i++) InvMod(x2, x1, p); t = GetTime()-t; cerr << "time for 1024-bit modular inverse: " << t*1000 << "us"; cerr << "\n"; // test modulus switching n = 1024; k = 1024; RandomLen(p, k); ZZ_p::init(p); if (!IsOdd(p)) p++; ZZ_pX j1, j2, j3; random(j1, n); random(j2, n); mul(j3, j1, j2); t = GetTime(); for (i = 0; i < 100; i++) mul(j3, j1, j2); t = GetTime()-t; cerr << "time to multiply degree 1023 polynomials\n modulo a 1024-bit number: "; cerr << (t/100) << "s"; cerr << "\n"; GF2X_time(); return 0; } ntl-11.5.1/src/ZZTest.cpp0000644417616742025610000001501014064716022016650 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT #define CHECK(x) do { if (!(x)) { cerr << "FAIL\n"; return -1; } } while(0) int main() { ZZ seed; RandomLen(seed, 30); SetSeed(seed); cerr << "\nseed=" << seed << "\n"; cerr << "\nvalidating RandomLen..."; for (long i = 1; i < 10000; i++) { ZZ x; RandomLen(x, i); CHECK(x.validate() && NumBits(x) == i); } cerr << "\nvalidating basic arithmetic..."; for (long i = 0; i < 200000; i++) { long a_len = RandomBnd(8000)+5; long b_len = RandomBnd(8000)+5; long c_len = RandomBnd(8000)+5; long d_len = RandomBnd(8000)+5; ZZ a, b, c, d; RandomLen(a, a_len); RandomLen(b, b_len); RandomLen(c, c_len); RandomLen(d, d_len); ZZ t1, t2; t1 = (a-b)*(c-d); t2 = a*c - a*d - b*c + b*d; CHECK(t1.validate() && t2.validate() && t1 == t2); long p = 7919; long d1 = rem(t1, p); long d2 = MulMod(rem(a-b, p), rem(c-d, p), p); CHECK(d1 == d2); } cerr << "\nvalidating DivRem..."; for (long i = 0; i < 200000; i++) { long b_len = RandomBnd(8000)+5; long q_len = RandomBnd(8000)+5; ZZ a, b, q, r, q1, r1; RandomLen(b, b_len); RandomLen(q, q_len); RandomBnd(r, b); a = b*q + r; DivRem(q1, r1, a, b); CHECK(q1.validate() && r1.validate() && q == q1 && r == r1); } cerr << "\nvalidating mul..."; for (long i = 0; i < 1000000; i++) { long a_len = RandomBnd(1000)+1; long b_len = RandomBnd(1000)+1; ZZ a, b, c; RandomLen(a, a_len); RandomLen(b, b_len); if (RandomBnd(2)) a = -a; if (RandomBnd(2)) b = -b; long p = 7919; long r = MulMod(rem(a, p), rem(b, p), p); long s = MulMod(rem(a, p), rem(a, p), p); switch (RandomBnd(5)) { case 0: mul(c, a, b); CHECK(c.validate() && rem(c, p) == r); break; case 1: mul(a, a, b); CHECK(a.validate() && rem(a, p) == r); break; case 2: mul(b, a, b); CHECK(b.validate() && rem(b, p) == r); break; case 3: mul(c, a, a); CHECK(c.validate() && rem(c, p) == s); break; case 4: mul(a, a, a); CHECK(a.validate() && rem(a, p) == s); break; } } cerr << "\nvalidating squaring..."; for (long i = 0; i < 1000000; i++) { long a_len = RandomBnd(1000)+1; ZZ a, b, a1, a2, c; RandomLen(a, a_len); if (RandomBnd(2)) a = -a; a1 = a; a2 = a; if (RandomBnd(2)) { sqr(b, a); mul(c, a1, a2); CHECK(b.validate() && c.validate() && b == c); } else { sqr(a, a); mul(c, a1, a2); CHECK(a.validate() && c.validate() && a == c); } } cerr << "\nvalidating SqrRoot..."; for (long i = 0; i < 200000; i++) { long a_len = RandomBnd(8000)+5; ZZ a, b; RandomLen(a, a_len); SqrRoot(b, a); CHECK(b.validate() && b*b <= a && (b+1)*(b+1) > a); } cerr << "\nvalidating shifts..."; for (long i = 0; i < 200000; i++) { long a_len = RandomBnd(5000)+5; long shamt = RandomBnd(a_len+100); ZZ a; RandomLen(a, a_len); ZZ t = ZZ(1); for (long k = 0; k < shamt; k++) t += t; ZZ xL, xR; LeftShift(xL, a, shamt); RightShift(xR, a, shamt); CHECK(xL.validate() && xR.validate()); CHECK(xL == a*t && xR == a/t); } cerr << "\nvalidating Preconditioned Remainder..."; for (long i = 0; i < 1000000; i++) { sp_ZZ_reduce_struct red_struct; long p_len = RandomBnd(NTL_SP_NBITS-1)+2; long p = RandomLen_long(p_len); long a_len = RandomBnd(30000)+5; ZZ a; RandomLen(a, a_len); red_struct.build(p); long r1 = red_struct.rem(a); long r2 = rem(a, p); CHECK(r1 == r2); } cerr << "\nvalidating MulAddTo..."; for (long i = 0; i < 1000000; i++) { long a_len = RandomBnd(4000)+5; long b_len = RandomBnd(4000)+5; long c_len = RandomBnd(4000)+5; long d_len = RandomBnd(4000)+5; ZZ a, b, c, d; RandomLen(a, a_len); RandomLen(b, b_len); RandomLen(c, c_len); RandomLen(d, d_len); ZZ t1, t2; t1 = a-b; t2 = c-d; long s_len, s; s_len = RandomBnd(NTL_NSP_NBITS)+1; s = RandomLen_long(s_len); if (RandomBnd(2)) s = -s; ZZ r1, r2; r1 = t1; MulAddTo(r1, t2, s); r2 = t1 + t2*s; CHECK(r1.validate() && r2.validate() && r1 == r2); } cerr << "\nvalidating GCD..."; for (long i = 0; i < 1000000; i++) { long a_len = RandomBnd(1000)+1; long b_len = RandomBnd(1000)+1; long c_len = RandomBnd(200)+1; ZZ a, b, c; RandomLen(a, a_len); RandomLen(b, b_len); RandomLen(c, c_len); a *= c; b *= c; if (RandomBnd(2)) a = -a; if (RandomBnd(2)) b = -b; ZZ d, s, t, d1; XGCD(d, s, t, a, b); GCD(d1, a, b); CHECK(d.validate() && s.validate() && t.validate() && d1.validate()); CHECK(d == d1 && d == a*s + b*t); CHECK(divide(a, d) && divide(b, d)); CHECK(abs(s) <= 1 || 2*d*abs(s) < abs(b)); CHECK(abs(t) <= 1 || 2*d*abs(t) < abs(a)); if (a < 0) { a = -a; s = -s; } if (b < 0) { b = -b; t = -t; } if (a < b) { swap(a, b); swap(s, t); } // so now we have a >= b >= 0 // check that s in (-b/2*d, b/2*d] CHECK(2*d*s > -b && 2*d*s <= b); } cerr << "\nvalidating InvMod..."; for (long i = 0; i < 100000; i++) { long n_len = RandomBnd(4000)+4; ZZ a, n, x; RandomLen(n, n_len); RandomBnd(a, n); long r = InvModStatus(x, a, n); CHECK((r == 0 && (x * a) % n == 1 && 0 <= x && x < n) || (r == 1 && x != 1 && x == GCD(a, n)) ); } cerr << "\nvalidating RatRecon..."; // This exercises RatRecon using the example from Section 4.6.1 // in A Computational Introduction to Number Theory for (long i = 0; i < 100000; i++) { long m_len = RandomBnd(4000)+5; ZZ m; RandomLen(m, m_len); ZZ t; RandomBnd(t, m); t += 1; ZZ s; RandomBnd(s, t); ZZ bnd = 2*m*m; long k = 0; ZZ ten_k = ZZ(1); while (ten_k <= bnd) { ten_k *= 10; k++; } ZZ z = (s*ten_k)/t; ZZ a, r, b; long res = ReconstructRational(r, b, z, ten_k, m, m); CHECK(res == 1); a = (b*z - r)/ten_k; CHECK(a*t == b*s); } cerr << "\n"; return 0; } ntl-11.5.1/src/SSMulTest.cpp0000644417616742025610000000304314064716022017313 0ustar gid-shoupvpug-gid-shoupv#include NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 2 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) void FillRandom(ZZX& f, long n, long k) { long sw = RandomBnd(2); f.SetLength(n); for (long i = 0; i < n; i++) { if (sw) { long kk = 1 + RandomBnd(k); RandomBits(f[i], kk); } else { long kk = RandomBnd(k); SetBit(f[i], kk); } if (RandomBnd(2)) NTL::negate(f[i], f[i]); } f.normalize(); } int main() { for (long iter = 0; iter < 4000; iter++) { if (iter % 100 == 0) cerr << "."; long na, nb, k; long sw = RandomBnd(3); if (sw == 0) { na = RandomBnd(20) + 1; nb = RandomBnd(20) + 1; k = RandomBnd(20) + 1; } else if (sw == 1) { na = RandomBnd(200) + 10; nb = RandomBnd(200) + 10; k = RandomBnd(200) + 10; } else { na = RandomBnd(3000) + 100; nb = RandomBnd(3000) + 100; k = RandomBnd(3000) + 100; } ZZX a, b, c, c1; FillRandom(a, na, k); FillRandom(b, nb, k); if (RandomBnd(2)) { SSMul(c, a, b); KarMul(c1, a, b); if (c != c1) Error("oops"); } else { SSSqr(c, a); KarSqr(c1, a); if (c != c1) Error("oops"); } } cerr << "\n"; } ntl-11.5.1/src/ZZ_pXTest.cpp0000644417616742025610000001476014064716022017332 0ustar gid-shoupvpug-gid-shoupv#include #include #include NTL_CLIENT #define ITER (500) void multest() { cerr << "mul"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long da, db; if (RandomBnd(2)) { da = RandomBnd(5000) + 100; db = RandomBnd(5000) + 100; } else { da = RandomBnd(200) + 1; db = RandomBnd(200) + 1; } ZZ_pX a, b, c1, c2; random(a, da); random(b, db); FFTMul(c1, a, b); ZZX A, B, C; conv(A, a); conv(B, b); mul(C, A, B); conv(c2, C); if (c1 != c2) { cerr << "******* oops\n"; break; } } cerr << "\n"; } void sqrtest() { cerr << "sqr"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long da = RandomBnd(5000) + 100; long db = RandomBnd(5000) + 100; ZZ_pX a, b, c1, c2; random(a, da); if (deg(a) < 80) { cerr << "*"; continue; } FFTSqr(c1, a); ZZX A, B, C; conv(A, a); sqr(C, A); conv(c2, C); if (c1 != c2) { cerr << "******* oops\n"; break; } } cerr << "\n"; } void mulmodtest() { cerr << "mulmod"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } ZZ_pX f; random(f, n); SetCoeff(f, n); ZZ_pXModulus F(f); ZZ_pX a, b, c1, c2; random(a, da); random(b, db); MulMod(c1, a, b, F); ZZX A, B, C; conv(A, a); conv(B, b); mul(C, A, B); conv(c2, C); rem(c2, c2, F); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void sqrmodtest() { cerr << "sqrmod"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } ZZ_pX f; random(f, n); SetCoeff(f, n); ZZ_pXModulus F(f); ZZ_pX a, b, c1, c2; random(a, da); random(b, db); SqrMod(c1, a, F); ZZX A, B, C; conv(A, a); conv(B, b); sqr(C, A); conv(c2, C); rem(c2, c2, F); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void mulmod1test() { cerr << "mulmod1"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } ZZ_pX f; random(f, n); SetCoeff(f, n); ZZ_pXModulus F(f); ZZ_pX a, b, c1, c2; random(a, da); random(b, db); ZZ_pXMultiplier bb; build(bb, b, F); MulMod(c1, a, bb, F); ZZX A, B, C; conv(A, a); conv(B, b); mul(C, A, B); conv(c2, C); rem(c2, c2, F); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } namespace NTL { void CopyReverse(ZZ_pX& x, const ZZ_pX& a, long lo, long hi); } struct ZZ_pXTransMultiplier { ZZ_pX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(ZZ_pXTransMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); ZZ_pX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, 0, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, 0, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, 0, db); } void TransMulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXTransMultiplier& B, const ZZ_pXModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); ZZ_pX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pXTransMultiplier& B, const ZZ_pXModulus& F) { ZZ_pX xx; TransMulMod(xx, to_ZZ_pX(a), B, F); x = xx.rep; } void updatetest() { cerr << "update"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } ZZ_pX f; random(f, n); SetCoeff(f, n); ZZ_pXModulus F(f); ZZ_pX a, b; random(a, da); random(b, db); ZZ_pXMultiplier bb1; build(bb1, b, F); ZZ_pXTransMultiplier bb2; build(bb2, b, F); Vec x1, x2; UpdateMap(x1, a.rep, bb1, F); UpdateMap(x2, a.rep, bb2, F); if (x1 != x2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void divremtest() { cerr << "divrem"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long dq = RandomBnd(n); ZZ_pX f; random(f, n); SetCoeff(f, n); ZZ_pXModulus F(f); ZZ_pX a, q, r, q1, r1; random(a, 2*n-1); DivRem(q, r, a, F); rem(r1, a, F); div(q1, a, F); if (deg(r) >= n || a != q*f + r || q != q1 || r != r1) { cerr << "******** oops\n"; break; } } cerr << "\n"; } int main() { ZZ p; GenPrime(p, 100); ZZ_p::init(p); multest(); sqrtest(); mulmodtest(); sqrmodtest(); mulmod1test(); divremtest(); updatetest(); #ifdef NTL_THREAD_BOOST GenPrime(p, 500); ZZ_p::init(p); SetNumThreads(4); cerr << "numthreads=4\n"; multest(); sqrtest(); mulmodtest(); sqrmodtest(); mulmod1test(); divremtest(); updatetest(); #endif } ntl-11.5.1/src/lzz_pXTest.cpp0000644417616742025610000001401614064716022017600 0ustar gid-shoupvpug-gid-shoupv#include NTL_CLIENT #define ITER (500) void multest() { cerr << "mul"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long da = RandomBnd(5000) + 100; long db = RandomBnd(5000) + 100; zz_pX a, b, c1, c2; random(a, da); random(b, db); if (deg(a) < 80 || deg(b) < 80) { cerr << "*"; continue; } FFTMul(c1, a, b); PlainMul(c2, a, b); if (c1 != c2) { cerr << "******* oops\n"; break; } } cerr << "\n"; } void sqrtest() { cerr << "sqr"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long da = RandomBnd(5000) + 100; long db = RandomBnd(5000) + 100; zz_pX a, b, c1, c2; random(a, da); if (deg(a) < 80) { cerr << "*"; continue; } FFTSqr(c1, a); PlainMul(c2, a, a); if (c1 != c2) { cerr << "******* oops\n"; break; } } cerr << "\n"; } void mulmodtest() { cerr << "mulmod"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } zz_pX f; random(f, n); SetCoeff(f, n); zz_pXModulus F(f); zz_pX a, b, c1, c2; random(a, da); random(b, db); MulMod(c1, a, b, F); PlainMul(c2, a, b); rem(c2, c2, f); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void sqrmodtest() { cerr << "sqrmod"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } zz_pX f; random(f, n); SetCoeff(f, n); zz_pXModulus F(f); zz_pX a, b, c1, c2; random(a, da); random(b, db); SqrMod(c1, a, F); PlainMul(c2, a, a); rem(c2, c2, f); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void mulmod1test() { cerr << "mulmod1"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } zz_pX f; random(f, n); SetCoeff(f, n); zz_pXModulus F(f); zz_pX a, b, c1, c2; random(a, da); random(b, db); zz_pXMultiplier bb; build(bb, b, F); MulMod(c1, a, bb, F); PlainMul(c2, a, b); rem(c2, c2, f); if (c1 != c2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } namespace NTL { void CopyReverse(zz_pX& x, const zz_pX& a, long lo, long hi); } struct zz_pXTransMultiplier { zz_pX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(zz_pXTransMultiplier& B, const zz_pX& b, const zz_pXModulus& F) { long db = deg(b); if (db >= F.n) LogicError("build TransMultiplier: bad args"); zz_pX t; LeftShift(t, b, F.n-1); div(t, t, F); // we optimize for low degree b long d; d = deg(t); if (d < 0) B.shamt_fbi = 0; else B.shamt_fbi = F.n-2 - d; CopyReverse(B.fbi, t, 0, d); // The following code optimizes the case when // f = X^n + low degree poly trunc(t, F.f, F.n); d = deg(t); if (d < 0) B.shamt = 0; else B.shamt = d; CopyReverse(B.f0, t, 0, d); if (db < 0) B.shamt_b = 0; else B.shamt_b = db; CopyReverse(B.b, b, 0, db); } void TransMulMod(zz_pX& x, const zz_pX& a, const zz_pXTransMultiplier& B, const zz_pXModulus& F) { if (deg(a) >= F.n) LogicError("TransMulMod: bad args"); zz_pX t1, t2; mul(t1, a, B.b); RightShift(t1, t1, B.shamt_b); mul(t2, a, B.f0); RightShift(t2, t2, B.shamt); trunc(t2, t2, F.n-1); mul(t2, t2, B.fbi); if (B.shamt_fbi > 0) LeftShift(t2, t2, B.shamt_fbi); trunc(t2, t2, F.n-1); LeftShift(t2, t2, 1); sub(x, t1, t2); } void UpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pXTransMultiplier& B, const zz_pXModulus& F) { zz_pX xx; TransMulMod(xx, to_zz_pX(a), B, F); x = xx.rep; } void updatetest() { cerr << "update"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long da = RandomBnd(n)+1; long db = RandomBnd(n)+1; if (RandomBnd(2)) { da = n; db = n; } zz_pX f; random(f, n); SetCoeff(f, n); zz_pXModulus F(f); zz_pX a, b; random(a, da); random(b, db); zz_pXMultiplier bb1; build(bb1, b, F); zz_pXTransMultiplier bb2; build(bb2, b, F); Vec x1, x2; UpdateMap(x1, a.rep, bb1, F); UpdateMap(x2, a.rep, bb2, F); if (x1 != x2) { cerr << "******** oops\n"; break; } } cerr << "\n"; } void divremtest() { cerr << "divrem"; for (long iter = 0; iter < ITER; iter++) { if (iter % 100 == 0) cerr << "."; long n = RandomBnd(5000) + 300; long dq = RandomBnd(n); zz_pX f; random(f, n); SetCoeff(f, n); zz_pXModulus F(f); zz_pX a, q, r, q1, r1; random(a, 2*n-1); DivRem(q, r, a, F); rem(r1, a, F); div(q1, a, F); if (deg(r) >= n || a != q*f + r || q != q1 || r != r1) { cerr << "******** oops\n"; break; } } cerr << "\n"; } int main() { long p; p = GenPrime_long(NTL_SP_NBITS); zz_p::init(p); multest(); sqrtest(); mulmodtest(); sqrmodtest(); mulmod1test(); divremtest(); updatetest(); zz_p::FFTInit(0); cerr << "FFT Prime\n"; multest(); sqrtest(); mulmodtest(); sqrmodtest(); mulmod1test(); divremtest(); updatetest(); } ntl-11.5.1/src/BerlekampTest.cpp0000644417616742025610000000237014064716022020214 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT long compare(const ZZ_pX& a, const ZZ_pX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (rep(a.rep[i]) < rep(b.rep[i])) return 0; if (rep(a.rep[i]) > rep(b.rep[i])) return 1; } return 0; } void sort(vec_pair_ZZ_pX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main() { ZZ p; cin >> p; ZZ_p::init(p); ZZ_pX f; cin >> f; vec_pair_ZZ_pX_long factors; double t = GetTime(); berlekamp(factors, f, 1); t = GetTime()-t; cerr << "total time: " << t << "\n"; ZZ_pX ff; mul(ff, factors); if (f != ff) TerminalError("Incorrect factorization!!"); sort(factors); cerr << "factorization pattern:"; long i; for (i = 0; i < factors.length(); i++) { cerr << " "; long k = factors[i].b; if (k > 1) cerr << k << "*"; cerr << deg(factors[i].a); } cerr << "\n"; cout << factors << "\n"; return 0; } ntl-11.5.1/src/CanZassTest.cpp0000644417616742025610000000236614064716022017661 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT long compare(const ZZ_pX& a, const ZZ_pX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (rep(a.rep[i]) < rep(b.rep[i])) return 0; if (rep(a.rep[i]) > rep(b.rep[i])) return 1; } return 0; } void sort(vec_pair_ZZ_pX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main() { ZZ p; cin >> p; ZZ_p::init(p); ZZ_pX f; cin >> f; vec_pair_ZZ_pX_long factors; double t = GetTime(); CanZass(factors, f, 1); t = GetTime()-t; cerr << "total time: " << t << "\n"; ZZ_pX ff; mul(ff, factors); if (f != ff) TerminalError("Incorrect factorization!!"); sort(factors); cerr << "factorization pattern:"; long i; for (i = 0; i < factors.length(); i++) { cerr << " "; long k = factors[i].b; if (k > 1) cerr << k << "*"; cerr << deg(factors[i].a); } cerr << "\n"; cout << factors << "\n"; return 0; } ntl-11.5.1/src/ZZXFacTest.cpp0000644417616742025610000000212614064716022017416 0ustar gid-shoupvpug-gid-shoupv#include NTL_CLIENT long compare(const ZZX& a, const ZZX& b) { if (deg(a) < deg(b)) return 0; if (deg(a) > deg(b)) return 1; long n = a.rep.length(); long i; for (i = 0; i < n; i++) { if (a.rep[i] < b.rep[i]) return 0; if (a.rep[i] > b.rep[i]) return 1; } return 0; } void sort(vec_pair_ZZX_long& v) { long n = v.length(); long i, j; for (i = 0; i < n-1; i++) for (j = 0; j < n-1-i; j++) if (compare(v[j].a, v[j+1].a)) { swap(v[j].a, v[j+1].a); swap(v[j].b, v[j+1].b); } } int main(int argc, char **argv) { ZZX f1, f; if (argc > 1) ZZXFac_MaxPrune = atoi(argv[1]); cin >> f; vec_pair_ZZX_long factors; ZZ c; double t; t = GetTime(); factor(c, factors, f, 0); t = GetTime()-t; cerr << "total time: " << t << "\n"; mul(f1, factors); mul(f1, f1, c); if (f != f1) TerminalError("FACTORIZATION INCORRECT!!!"); sort(factors); cout << c << "\n"; cout << factors << "\n"; return 0; } ntl-11.5.1/src/MoreFacTest.cpp0000644417616742025610000000177614064716022017637 0ustar gid-shoupvpug-gid-shoupv#include NTL_CLIENT long NumFacs(const vec_pair_ZZX_long& v) { long i; long res; res = 0; for (i = 0; i < v.length(); i++) res += v[i].b; return res; } int main() { long cnt = 0; while (SkipWhiteSpace(cin)) { cnt++; cerr << "."; vec_ZZ w; ZZX f1, f; long nfacs; cin >> w; cin >> nfacs; long i, n; n = w.length(); f.rep.SetLength(n); for (i = 0; i < n; i++) f.rep[i] = w[n-1-i]; f.normalize(); vec_pair_ZZX_long factors; ZZ c; factor(c, factors, f, 0); mul(f1, factors); mul(f1, f1, c); if (f != f1) { cerr << f << "\n"; cerr << c << " " << factors << "\n"; TerminalError("FACTORIZATION INCORRECT (1) !!!"); } long nfacs1 = NumFacs(factors); if (nfacs1 != nfacs) TerminalError("FACTORIZATION INCORRECT (2) !!!"); } cerr << "\n"; cerr << "MoreFacTest OK\n"; return 0; } ntl-11.5.1/src/LLLTest.cpp0000644417616742025610000000546414064716022016744 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT int main() { mat_ZZ B; long s; #if 1 cin >> B; #else long i, j; long n; cerr << "n: "; cin >> n; long m; cerr << "m: "; cin >> m; long k; cerr << "k: "; cin >> k; B.SetDims(n, m); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) { RandomLen(B(i,j), k); if (RandomBnd(2)) negate(B(i,j), B(i,j)); } #endif mat_ZZ U, B0, B1, B2; B0 = B; double t; ZZ d; B = B0; cerr << "LLL_FP..."; t = GetTime(); s = LLL_FP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "LLL_QP..."; t = GetTime(); s = LLL_QP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "LLL_XD..."; t = GetTime(); s = LLL_XD(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "LLL_RR..."; t = GetTime(); s = LLL_RR(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "G_LLL_FP..."; t = GetTime(); s = G_LLL_FP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "G_LLL_QP..."; t = GetTime(); s = G_LLL_QP(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "G_LLL_XD..."; t = GetTime(); s = G_LLL_XD(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "G_LLL_RR..."; t = GetTime(); s = G_LLL_RR(B, U, 0.99); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); LLL(d, B, 90, 100); if (B1 != B) TerminalError("bad LLLTest (2)"); B = B0; cerr << "LLL..."; t = GetTime(); s = LLL(d, B, U); cerr << (GetTime()-t) << "\n"; mul(B1, U, B0); if (B1 != B) TerminalError("bad LLLTest (1)"); cout << "rank = " << s << "\n"; cout << "det = " << d << "\n"; cout << "B = " << B << "\n"; cout << "U = " << U << "\n"; } ntl-11.5.1/src/subset.cpp0000644417616742025610000000516214064716022016761 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT long SubsetSumSolution(const vec_ZZ& z) { long n = z.length()-3; long j; if (z(n+1) != 0) return 0; if (z(n+2) != -1 && z(n+2) != 1) return 0; for (j = 1; j <= n; j++) if (z(j) != -1 && z(j) != 1) return 0; return 1; } int main() { RR::SetPrecision(150); long n, b, size; cerr << "n: "; cin >> n; cerr << "b: "; cin >> b; cerr << "size: "; cin >> size; cerr << "prune: "; long prune; cin >> prune; ZZ seed; cerr << "seed: "; cin >> seed; if (seed != 0) SetSeed(seed); char alg; cerr << "alg [fqQxr]: "; cin >> alg; double TotalTime = 0; long TotalSucc = 0; long iter; for (iter = 1; iter <= 20; iter++) { vec_ZZ a; a.SetLength(n); ZZ bound; LeftShift(bound, to_ZZ(1), b); long i; for (i = 1; i <= n; i++) { RandomBnd(a(i), bound); a(i) += 1; } ZZ S; do { RandomLen(S, n+1); } while (weight(S) != n/2+1); ZZ s; clear(s); for (i = 1; i <= n; i++) if (bit(S, i-1)) s += a(i); mat_ZZ B(INIT_SIZE, n+1, n+3); for (i = 1; i <= n; i++) { B(i, i) = 2; B(i, n+1) = a(i) * n; B(i, n+3) = n; } for (i = 1; i <= n; i++) B(n+1, i) = 1; B(n+1, n+1) = s * n; B(n+1, n+2) = 1; B(n+1, n+3) = n; B(n+1, n+3) *= n/2; swap(B(1), B(n+1)); for (i = 2; i <= n; i++) { long j = RandomBnd(n-i+2) + i; swap(B(i), B(j)); } double t; LLLStatusInterval = 10; t = GetTime(); switch (alg) { case 'f': BKZ_FP(B, 0.99, size, prune, SubsetSumSolution); break; case 'q': BKZ_QP(B, 0.99, size, prune, SubsetSumSolution); break; case 'Q': BKZ_QP1(B, 0.99, size, prune, SubsetSumSolution); break; case 'x': BKZ_XD(B, 0.99, size, prune, SubsetSumSolution); break; case 'r': BKZ_RR(B, 0.99, size, prune, SubsetSumSolution); break; default: TerminalError("invalid algorithm"); } t = GetTime()-t; long succ = 0; for (i = 1; i <= n+1; i++) if (SubsetSumSolution(B(i))) succ = 1; TotalTime += t; TotalSucc += succ; if (succ) cerr << "+"; else cerr << "-"; } cerr << "\n"; cerr << "number of success: " << TotalSucc << "\n"; cerr << "average time: " << TotalTime/20 << "\n"; return 0; } ntl-11.5.1/src/MatrixTest.cpp0000644417616742025610000000145014064716022017554 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_CLIENT int main() { mat_ZZ B, X; vec_ZZ v, w; cin >> B; cin >> v; ZZ d; double t; cerr << "matrix inverse..."; t = GetTime(); inv(d, X, B); cerr << (GetTime()-t) << "\n"; cout << d << "\n"; cout << X << "\n"; cout << "\n\n\n"; cerr << "hensel solve..."; t = GetTime(); HenselSolve1(d, w, B, v); cerr << (GetTime()-t) << "\n"; cout << d << "\n"; cout << w << "\n"; cout << "\n\n\n"; ZZX f; cerr << "char poly..."; t = GetTime(); CharPoly(f, B); cerr << (GetTime()-t) << "\n"; cout << f << "\n"; cout << "\n\n\n"; cerr << "HNF..."; t = GetTime(); HNF(X, B, d); cerr << (GetTime()-t) << "\n"; cout << X; return 0; } ntl-11.5.1/src/mat_lzz_pTest.cpp0000644417616742025610000001221414064716022020307 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT void FillRandom(Mat& A) { long n = A.NumRows(); long m = A.NumCols(); for (long i = 0; i < n; i++) for (long j = 0; j < m; j++) random(A[i][j]); } void FillRandom1(Mat& A) { long n = A.NumRows(); long m = A.NumCols(); long r; long choice = RandomBnd(5); if (choice == 0 || n == 0) { r = 0; } else if (choice == 1) { r = min(n, 1+RandomBnd(10)); } else { r = 1+RandomBnd(n); } Mat B, C; B.SetDims(n, n); FillRandom(B); C.SetDims(n, m); for (long i = 0; i < r; i++) for (long j = 0; j < m; j++) random(C[i][j]); mul(A, B, C); } void FillRandom(Vec& A) { long n = A.length(); for (long i = 0; i < n; i++) random(A[i]); } long old_gauss(mat_zz_p& M, long w) { using NTL_NAMESPACE::negate; long k, l; long i, j; long pos; zz_p t1, t2, t3; zz_p *x, *y; long n = M.NumRows(); long m = M.NumCols(); if (w < 0 || w > m) LogicError("gauss: bad args"); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long T1, T2; l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { if (!IsZero(M[i][k])) { pos = i; break; } } if (pos != -1) { swap(M[pos], M[l]); inv(t3, M[l][k]); negate(t3, t3); for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 mul(t1, M[i][k], t3); T1 = rep(t1); mulmod_precon_t T1pinv = PrepMulModPrecon(T1, p, pinv); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 T2 = MulModPrecon(rep(*y), T1, p, T1pinv); T2 = AddMod(T2, rep(*x), p); (*x).LoopHole() = T2; } } l++; } } return l; } long old_gauss(mat_zz_p& M) { return old_gauss(M, M.NumCols()); } void old_image(mat_zz_p& X, const mat_zz_p& A) { mat_zz_p M; M = A; long r = old_gauss(M); M.SetDims(r, M.NumCols()); X = M; } int main(int argc, char **argv) { ZZ seed; RandomLen(seed, 30); SetSeed(seed); cerr << "\nseed=" << seed << "\n"; long iters = 100; #if 1 cerr << "testing multiplication"; for (long cnt = 0; cnt < iters; cnt++) { cerr << "."; long bnd = (cnt%2) ? 25 : 2000; long len = RandomBnd(NTL_SP_NBITS-3)+4; long n = RandomBnd(bnd); long l = RandomBnd(bnd); long m = RandomBnd(bnd); long p = RandomPrime_long(len); zz_p::init(p); Mat A, B, X; A.SetDims(n, l); B.SetDims(l, m); FillRandom(A); FillRandom(B); X.SetDims(n, m); vec_zz_p R; R.SetLength(m); for (long i = 0; i < m; i++) random(R[i]); mul(X, A, B); if (X*R != A*(B*R)) cerr << "*\n*\n*\n*\n*\n*********** oops " << len << " " << n << " " << l << " " << m << "\n"; } #endif #if 1 cerr << "\ntesting inversion"; for (long cnt = 0; cnt < iters; cnt++) { cerr << "."; long bnd = (cnt%2) ? 25 : 1500; long len = RandomBnd(NTL_SP_NBITS-3)+4; long n = RandomBnd(bnd); long p = RandomPrime_long(len); zz_p::init(p); Mat A, X; A.SetDims(n, n); FillRandom(A); vec_zz_p R; R.SetLength(n); for (long i = 0; i < n; i++) random(R[i]); zz_p d; inv(d, X, A); if (d != 0) { if (R != A*(X*R)) cerr << "\n*\n*\n*\n*\n*********** oops " << len << " " << n << "\n"; } else { cerr << "[singular]"; } } #endif #if 1 cerr << "\ntesting solve"; for (long cnt = 0; cnt < iters; cnt++) { cerr << "."; long bnd = (cnt%2) ? 25 : 2000; long len = RandomBnd(NTL_SP_NBITS-3)+4; long n = RandomBnd(bnd); long p = RandomPrime_long(len); zz_p::init(p); Mat A; A.SetDims(n, n); FillRandom(A); Vec x, b; b.SetLength(n); FillRandom(b); zz_p d; solve(d, A, x, b); if (d != 0) { if (A*x != b) cerr << "\n*\n*\n*\n*\n*********** oops " << len << " " << n << "\n"; } else { cerr << "[singular]"; } } #endif #if 1 cerr << "\ntesting image and kernel"; for (long cnt = 0; cnt < 4*iters; cnt++) { cerr << "."; long bnd = (cnt%2) ? 25 : 1500; long len = RandomBnd(NTL_SP_NBITS-3)+4; long n = RandomBnd(bnd); long m = RandomBnd(bnd); long p = RandomPrime_long(len); zz_p::init(p); Mat A; A.SetDims(n, m); FillRandom1(A); Mat im, im1, ker1; old_image(im, A); image(im1, A); kernel(ker1, A); //cerr << n << ":" << ":" << m << ":" << im.NumRows() << "||"; if (im != im1 || !IsZero(ker1*A) || im1.NumRows() + ker1.NumRows() != n) { cerr << "\n*\n*\n*\n*\n*********** oops " << len << " " << n << m << "\n"; } } #endif cerr << "\n"; } ntl-11.5.1/src/CharPolyTest.cpp0000644417616742025610000000032514064716022020031 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT int main() { ZZX a, f, g; cin >> a; cin >> f; double t = GetTime();; CharPolyMod(g, a, f); cerr << GetTime()-t << "\n"; cout << g << "\n"; return 0; } ntl-11.5.1/src/RRTest.cpp0000644417616742025610000000045014064716022016632 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT int main() { mat_RR A; vec_RR x, y, z; RR d; RR::SetPrecision(200); cin >> A; cin >> y; solve(d, x, A, y); // mul(z, x, A); // sub(z, z, y); z = x*A - y; cout << d << "\n"; cout << x << "\n"; cout << z << "\n"; } ntl-11.5.1/src/QuadTest.cpp0000644417616742025610000000333414064716022017205 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT int main() { quad_float a, b, c, d; quad_float::SetOutputPrecision(25); long pok; double one = 1.0; quad_float_PrecisionOK(pok, one); if (pok) cout << "Precision OK\n"; else cout << "Precision not OK\n"; cin >> a; cout << a << "\n"; cin >> b; cout << b << "\n"; c = a + b; d = a; d += b; cout << c << "\n"; cout << d << "\n"; c = a - b; d = a; d -= b; cout << c << "\n"; cout << d << "\n"; c = a * b; d = a; d *= b; cout << c << "\n"; cout << d << "\n"; c = a / b; d = a; d /= b; cout << c << "\n"; cout << d << "\n"; c = -a; cout << c << "\n"; c = sqrt(a); cout << c << "\n"; power(c, to_quad_float(10), 20); cout << c << "\n"; { long n, n1; int shamt = min(NTL_BITS_PER_LONG,2*NTL_DOUBLE_PRECISION); n = to_long((1UL << (shamt-1)) - 1UL); c = to_quad_float(n); n1 = to_long(c); if (n1 == n) cout << "long conversion OK\n"; else cout << "long conversion not OK\n"; n = to_long(1UL << (shamt-1)); c = to_quad_float(n); n1 = to_long(c); if (n1 == n) cout << "long conversion OK\n"; else cout << "long conversion not OK\n"; } { unsigned long n; ZZ n1; int shamt = min(NTL_BITS_PER_LONG,2*NTL_DOUBLE_PRECISION); n = (1UL << (shamt-1)) - 1UL; c = to_quad_float(n); n1 = to_ZZ(c); if (n1 == to_ZZ(n)) cout << "ulong conversion OK\n"; else cout << "ulong conversion not OK\n"; n = 1UL << (shamt-1); c = to_quad_float(n); n1 = to_ZZ(c); if (n1 == to_ZZ(n)) cout << "ulong conversion OK\n"; else cout << "ulong conversion not OK\n"; } } ntl-11.5.1/src/GF2XTest.cpp0000644417616742025610000000344714064716022017026 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT struct wd { int amt; wd(int x) { amt = x; } }; #define WD(x,y) wd(x) << (y) ostream& operator<<(ostream& s, const wd& w) { s.width(w.amt); return s; } int main() { long n; GF2X a, b, c, c1, ss, ss1, tt, tt1; double t; long iter, i; cout << WD(12,"n") << WD(12,"OldGCD") << WD(12,"GCD") << WD(12,"OldXGCD") << WD(12, "XGCD") << "\n"; cout.precision(3); cout.setf(ios::scientific); for (n = 32; n <= (1L << 18); n = n << 3) { random(a, n); random(b, n); OldGCD(c, a, b); GCD(c1, a, b); OldXGCD(c, ss, tt, a, b); XGCD(c1, ss1, tt1, a, b); if (c1 != c || ss1 != ss || tt1 != tt || ss*a + tt*b != c) { cerr << "**** GF2XTest FAILED!\n"; return 1; } cout << WD(12,n); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldGCD(c, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) GCD(c, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) OldXGCD(c, ss, tt, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); iter = 0; do { iter = iter ? (2*iter) : 1; t = GetTime(); for (i = 0; i < iter; i++) XGCD(c, ss, tt, a, b); t = GetTime()-t; } while (t < 0.5); cout << WD(12,t/iter); cout << "\n"; } return 0; } ntl-11.5.1/src/GF2EXTest.cpp0000644417616742025610000000406214064716022017125 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_OPEN_NNS void PlainMul(GF2EX&, const GF2EX&, const GF2EX&); NTL_CLOSE_NNS NTL_CLIENT int main() { GF2X p; BuildIrred(p, 200); GF2E::init(p); GF2EX f; SetCoeff(f, 41); SetCoeff(f, 1); SetCoeff(f, 0); GF2X a; SetCoeff(a, 117); SetCoeff(a, 10); SetCoeff(a, 0); GF2EX g, h; SetX(g); SetCoeff(g, 0, to_GF2E(a)); MinPolyMod(h, g, f); f = h; vec_pair_GF2EX_long u; CanZass(u, f, 1); cerr << "factorization pattern:"; long i; for (i = 0; i < u.length(); i++) { cerr << " "; long k = u[i].b; if (k > 1) cerr << k << "*"; cerr << deg(u[i].a); } cerr << "\n\n\n"; GF2EX ff; mul(ff, u); if (f != ff || u.length() != 11) { cerr << "GF2EXTest NOT OK\n"; return 1; } { cerr << "multiplication test...\n"; BuildIrred(p, 512); GF2E::init(p); GF2EX A, B, C, C1; random(A, 512); random(B, 512); double t; long i; t = GetTime(); for (i = 0; i < 10; i++) PlainMul(C, A, B); t = GetTime() - t; cerr << "time for plain mul of degree 511 over GF(2^512): " << (t/10) << "s\n"; t = GetTime(); for (i = 0; i < 10; i++) mul(C1, A, B); t = GetTime() - t; cerr << "time for karatsuba mul of degree 511 over GF(2^512): " << (t/10) << "s\n"; if (C != C1) { cerr << "GF2EXTest NOT OK\n"; return 1; } } { cerr << "multiplication test...\n"; BuildIrred(p, 16); GF2E::init(p); GF2EX A, B, C, C1; random(A, 512); random(B, 512); double t; t = GetTime(); for (i = 0; i < 10; i++) PlainMul(C, A, B); t = GetTime() - t; cerr << "time for plain mul of degree 511 over GF(2^16): " << (t/10) << "s\n"; t = GetTime(); for (i = 0; i < 10; i++) mul(C1, A, B); t = GetTime() - t; cerr << "time for karatsuba mul of degree 511 over GF(2^16): " << (t/10) << "s\n"; if (C != C1) { cerr << "GF2EXTest NOT OK\n"; return 1; } } cerr << "GF2EXTest OK\n"; return 0; } ntl-11.5.1/src/GF2EXGCDTest.cpp0000644417616742025610000000373114064716022017445 0ustar gid-shoupvpug-gid-shoupv#include #include NTL_CLIENT void test(GF2X& P, GF2EX& f, GF2EX& g, GF2EX& h, GF2EX& hx, GF2EX& s, GF2EX& t) { /* P is the polynomial of the extension * f and g the polynomials * h the gcd * hx the gcd obtained using XGCD * s, t are Bezout coefficients hx=f*s+g*t */ GF2EX htest,rf,rg; if (h!=hx){ cout << P << "\n" << f << "\n" << g << "\n"; Error("different gcd:\n"); } if (max(deg(f), deg(g)) > 0 || min(deg(f), deg(g)) >= 0) { if (deg(s) >= deg(g) || deg(t) >= deg(f)) { cout << P << "\n" << f << "\n" << g << "\n"; Error("degree bounds at fault:\n"); } } mul(s,s,f); mul(t,t,g); add(htest,t,s); if (h!=htest){ cout << P << "\n" << f << "\n" << g << "\n"; Error("xgcd at fault:\n"); } if (!IsZero(h)){ rem(rf,f,h); rem(rg,f,h); if ((!IsZero(rf))||(!IsZero(rg))){ cout << P << "\n" << f << "\n" << g << "\n"; Error("not a common divisor\n"); } }else{ if (!IsZero(f) && !IsZero(g)){ cout << "debug:\n"; cout << P << "\n" << f << "\n" << g << "\n" << h << "\n"; Error("ooops:\n"); } } } int main() { GF2X P; BuildIrred(P, 128); GF2E::init(P); for (long i = 0; i < 400; i++) { if (i%10 == 0) cerr << "."; GF2EX f,g,h,s,t,hx; long deg_h; if (RandomBnd(2)) deg_h = RandomBnd(10)+1; else deg_h = RandomBnd(500)+1; random(h, deg_h); SetCoeff(h, deg_h); long deg_f; if (RandomBnd(2)) deg_f = RandomBnd(10)+1; else deg_f = RandomBnd(1000)+1; random(f, deg_f); f *= h; long deg_g; if (RandomBnd(2)) deg_g = RandomBnd(10)+1; else deg_g = RandomBnd(1000)+1; random(g, deg_g); g *= h; h = 0; GCD(h, f, g); XGCD(hx, s, t, f, g); test(P, f, g, h, hx, s, t); } cerr << "\n"; } ntl-11.5.1/src/BitMatTest.cpp0000644417616742025610000000221614064716022017471 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT void cvt(mat_GF2& x, const mat_zz_p& a) { long n = a.NumRows(); long m = a.NumCols(); x.SetDims(n, m); long i, j; for (i = 0; i < n; i++) for (j = 0; j < m; j++) x.put(i, j, rep(a[i][j])); } void cvt(vec_GF2& x, const vec_zz_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) x.put(i, rep(a[i])); } int main() { zz_p::init(2); long i; vec_GF2 v; v.SetLength(5); v[1] = 1; v[0] = v[1]; if (v[0] != v[1]) TerminalError("BitMatTest not OK!!"); for (i=0; i < 8; i++) { mat_zz_p a, x; mat_GF2 A, X, X1; long n = RandomBnd(500) + 1; long m = RandomBnd(500) + 1; cerr << n << " " << m << "\n"; double t; random(a, n, m); t = GetTime(); image(x, a); t = GetTime() - t; cerr << t << "\n"; cvt(A, a); t = GetTime(); image(X, A); t = GetTime() - t; cerr << t << "\n"; cvt(X1, x); if (X1 != X) TerminalError("BitMatTest NOT OK!!"); cerr << "\n"; } cerr << "BitMatTest OK\n"; } ntl-11.5.1/src/ZZ_pEXTest.cpp0000644417616742025610000000153114064716022017427 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT int main() { ZZ_p::init(to_ZZ(17)); ZZ_pX P; BuildIrred(P, 10); ZZ_pE::init(P); ZZ_pEX f, g, h; random(f, 20); SetCoeff(f, 20); random(h, 20); g = MinPolyMod(h, f); if (deg(g) < 0) TerminalError("bad ZZ_pEXTest (1)"); if (CompMod(g, h, f) != 0) TerminalError("bad ZZ_pEXTest (2)"); vec_pair_ZZ_pEX_long v; long j; for (j = 0; j < 5; j++) { long n = RandomBnd(40)+10; cerr << n << " "; random(f, n); SetCoeff(f, n); v = CanZass(f); g = mul(v); if (f != g) cerr << "oops1\n"; long i; for (i = 0; i < v.length(); i++) if (!DetIrredTest(v[i].a)) TerminalError("bad ZZ_pEXTest (3)"); } cerr << "\n"; cerr << "ZZ_pEXTest OK\n"; } ntl-11.5.1/src/ZZ_pEXGCDTest.cpp0000644417616742025610000000407714064716022017755 0ustar gid-shoupvpug-gid-shoupv#include #include NTL_CLIENT void test(ZZ_pX& P, ZZ_pEX& f, ZZ_pEX& g, ZZ_pEX& h, ZZ_pEX& hx, ZZ_pEX& s, ZZ_pEX& t) { /* P is the polynomial of the extension * f and g the polynomials * h the gcd * hx the gcd obtained using XGCD * s, t are Bezout coefficients hx=f*s+g*t */ ZZ_pEX htest,rf,rg; if (h!=hx){ cout << P << "\n" << f << "\n" << g << "\n"; Error("different gcd:\n"); } if (max(deg(f), deg(g)) > 0 || min(deg(f), deg(g)) >= 0) { if (deg(s) >= deg(g) || deg(t) >= deg(f)) { cout << P << "\n" << f << "\n" << g << "\n"; Error("degree bounds at fault:\n"); } } mul(s,s,f); mul(t,t,g); add(htest,t,s); if (h!=htest){ cout << P << "\n" << f << "\n" << g << "\n"; Error("xgcd at fault:\n"); } if (!IsZero(h)){ rem(rf,f,h); rem(rg,f,h); if ((!IsZero(rf))||(!IsZero(rg))){ cout << P << "\n" << f << "\n" << g << "\n"; Error("not a common divisor\n"); } }else{ if (!IsZero(f) && !IsZero(g)){ cout << "debug:\n"; cout << P << "\n" << f << "\n" << g << "\n" << h << "\n"; Error("ooops:\n"); } } } int main() { ZZ prime = conv("340282366920938463463374607619092730237"); ZZ_p::init(prime); ZZ_pX P; BuildIrred(P, 3); ZZ_pE::init(P); for (long i = 0; i < 400; i++) { if (i%10 == 0) cerr << "."; ZZ_pEX f,g,h,s,t,hx; long deg_h; if (RandomBnd(2)) deg_h = RandomBnd(10)+1; else deg_h = RandomBnd(500)+1; random(h, deg_h); SetCoeff(h, deg_h); long deg_f; if (RandomBnd(2)) deg_f = RandomBnd(10)+1; else deg_f = RandomBnd(1000)+1; random(f, deg_f); f *= h; long deg_g; if (RandomBnd(2)) deg_g = RandomBnd(10)+1; else deg_g = RandomBnd(1000)+1; random(g, deg_g); g *= h; h = 0; GCD(h, f, g); XGCD(hx, s, t, f, g); test(P, f, g, h, hx, s, t); } cerr << "\n"; } ntl-11.5.1/src/lzz_pEXTest.cpp0000644417616742025610000000152414064716022017705 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT int main() { zz_p::init(17); zz_pX P; BuildIrred(P, 10); zz_pE::init(P); zz_pEX f, g, h; random(f, 20); SetCoeff(f, 20); random(h, 20); g = MinPolyMod(h, f); if (deg(g) < 0) TerminalError("bad zz_pEXTest (1)"); if (CompMod(g, h, f) != 0) TerminalError("bad zz_pEXTest (2)"); vec_pair_zz_pEX_long v; long j; for (j = 0; j < 5; j++) { long n = RandomBnd(40)+10; cerr << n << " "; random(f, n); SetCoeff(f, n); v = CanZass(f); g = mul(v); if (f != g) cerr << "oops1\n"; long i; for (i = 0; i < v.length(); i++) if (!DetIrredTest(v[i].a)) TerminalError("bad zz_pEXTest (3)"); } cerr << "\n"; cerr << "zz_pEXTest OK\n"; } ntl-11.5.1/src/lzz_pEXGCDTest.cpp0000644417616742025610000000402214064716022020217 0ustar gid-shoupvpug-gid-shoupv#include #include NTL_CLIENT void test(zz_pX& P, zz_pEX& f, zz_pEX& g, zz_pEX& h, zz_pEX& hx, zz_pEX& s, zz_pEX& t) { /* P is the polynomial of the extension * f and g the polynomials * h the gcd * hx the gcd obtained using XGCD * s, t are Bezout coefficients hx=f*s+g*t */ zz_pEX htest,rf,rg; if (h!=hx){ cout << P << "\n" << f << "\n" << g << "\n"; Error("different gcd:\n"); } if (max(deg(f), deg(g)) > 0 || min(deg(f), deg(g)) >= 0) { if (deg(s) >= deg(g) || deg(t) >= deg(f)) { cout << P << "\n" << f << "\n" << g << "\n"; Error("degree bounds at fault:\n"); } } mul(s,s,f); mul(t,t,g); add(htest,t,s); if (h!=htest){ cout << P << "\n" << f << "\n" << g << "\n"; Error("xgcd at fault:\n"); } if (!IsZero(h)){ rem(rf,f,h); rem(rg,f,h); if ((!IsZero(rf))||(!IsZero(rg))){ cout << P << "\n" << f << "\n" << g << "\n"; Error("not a common divisor\n"); } }else{ if (!IsZero(f) && !IsZero(g)){ cout << "debug:\n"; cout << P << "\n" << f << "\n" << g << "\n" << h << "\n"; Error("ooops:\n"); } } } int main() { long prime = 17; zz_p::init(prime); zz_pX P; BuildIrred(P, 5); zz_pE::init(P); for (long i = 0; i < 400; i++) { if (i%10 == 0) cerr << "."; zz_pEX f,g,h,s,t,hx; long deg_h; if (RandomBnd(2)) deg_h = RandomBnd(10)+1; else deg_h = RandomBnd(500)+1; random(h, deg_h); SetCoeff(h, deg_h); long deg_f; if (RandomBnd(2)) deg_f = RandomBnd(10)+1; else deg_f = RandomBnd(1000)+1; random(f, deg_f); f *= h; long deg_g; if (RandomBnd(2)) deg_g = RandomBnd(10)+1; else deg_g = RandomBnd(1000)+1; random(g, deg_g); g *= h; h = 0; GCD(h, f, g); XGCD(hx, s, t, f, g); test(P, f, g, h, hx, s, t); } cerr << "\n"; } ntl-11.5.1/src/Timing.cpp0000644417616742025610000001026514064716022016703 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 4 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) int main() { double t; long k = 1000; long n = 1000; { SetSeed(conv(1)); ZZ p = RandomPrime_ZZ(k); ZZ_p::init(p); ZZ x, y, z, w, s1, s2; SetSeed(conv(2)); RandomBnd(x, p); SetSeed(conv(3)); RandomBnd(y, p); TIME_IT(t, mul(z, x, y)); cout << "multiply 1000-bit ints: " << t << "\n"; TIME_IT(t, sqr(w, x)); cout << "square 1000-bit ints: " << t << "\n"; TIME_IT(t, rem(w, z, p)); cout << "remainder 2000/1000-bit ints: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 1000-bit ints: " << t << "\n"; TIME_IT(t, XGCD(w, s1, s2, x, y)); cout << "xgcd 1000-bit ints: " << t << "\n"; TIME_IT(t, PowerMod(w, x, y, p)); cout << "power mod 1000-bit ints: " << t << "\n"; ZZ_pX a, b, c; SetSeed(conv(4)); random(a, n); SetSeed(conv(5)); random(b, n); mul(c, a, b); TIME_IT(t, mul(c, a, b)); cout << "multiply degree-1000 poly mod 1000-bit prime: " << t << "\n"; ZZ_pX f; SetSeed(conv(6)); random(f, n); SetCoeff(f, n); ZZ_pX A, B; SetSeed(conv(7)); random(A, 2*(deg(f)-1)); TIME_IT(t, rem(B, A, f)); cout << "remainder degree-2000/1000 poly mod 1000-bit prime: " << t << "\n"; ZZ_pXModulus F(f); TIME_IT(t, rem(B, A, F)); cout << "preconditioned remainder degree-2000/1000 poly mod 1000-bit prime: " << t << "\n"; TIME_IT(t, GCD(a, b)); cout << "gcd degree-1000 poly mod 1000-bit prime: " << t << "\n"; ZZX AA = conv(a); ZZX BB = conv(b); ZZX CC; TIME_IT(t, mul(CC, AA, BB)); cout << "multiply degree-1000 int poly with 1000-bit coeffs: " << t << "\n"; cout << "\n"; cout << "factoring degree-1000 poly mod 1000-bit prime...\n"; TIME_IT(t, CanZass(f, _cnt == 0)); cout << "...total time = " << t << "\n\n"; } { n = 500; k = 500; SetSeed(conv(8)); GF2X p = BuildRandomIrred(BuildIrred_GF2X(k)); GF2E::init(p); GF2X x, y, z, w; SetSeed(conv(9)); random(x, deg(p)); SetSeed(conv(10)); random(y, deg(p)); TIME_IT(t, mul(z, x, y)); cout << "multiply 500-bit GF2Xs: " << t << "\n"; TIME_IT(t, rem(w, z, p)); cout << "remainder 1000/500-bit GF2Xs: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 500-bit GF2Xs: " << t << "\n"; SetSeed(conv(11)); GF2X fff; random(fff, k); SetCoeff(fff, k); cout << "\n"; TIME_IT(t, CanZass(fff, 0)); cout << "factoring degree-500 GF2X: " << t << "\n"; TIME_IT(t, GCD(w, x, y)); cout << "gcd 500-bit GF2X: " << t << "\n"; GF2EX a, b, c; SetSeed(conv(12)); random(a, n); SetSeed(conv(13)); random(b, n); mul(c, a, b); TIME_IT(t, mul(c, a, b)); cout << "multiply degree-500 poly mod 500-bit GF2X: " << t << "\n"; GF2EX f; SetSeed(conv(14)); random(f, n); SetCoeff(f, n); GF2EX A, B; SetSeed(conv(15)); random(A, 2*(deg(f)-1)); TIME_IT(t, rem(B, A, f)); cout << "remainder degree-1000/500 poly mod 500-bit GF2X: " << t << "\n"; GF2EXModulus F(f); TIME_IT(t, rem(B, A, F)); cout << "preconditioned remainder degree-1000/500 poly mod 500-bit GF2X: " << t << "\n"; TIME_IT(t, GCD(a, b)); cout << "gcd degree-500 poly mod 500-bit GF2X: " << t << "\n"; f = f >> n/2; cout << "\n"; cout << "factoring degree-500 poly mod 500-bit GF2X...\n"; TIME_IT(t, CanZass(f, _cnt == 0)); cout << "\n...total time = " << t << "\n"; } } ntl-11.5.1/src/ThreadTest.cpp0000644417616742025610000000444014064716022017521 0ustar gid-shoupvpug-gid-shoupv#include #ifdef NTL_THREADS #include #include #include #include NTL_CLIENT #if 1 long mobius(long n) { long p,e,arity=0; PrimeSeq s; while (n!=1) { p=s.next(); e=0; while ((n%p==0)) { n=n/p; e++; } if (e>1) { return 0; } if (e!=0) { arity^=1; } } if (arity==0) { return 1; } return -1; } ZZX Cyclotomic(long N) { ZZX Num,Den,G,F; set(Num); set(Den); long m,d; for (d=1; d<=N; d++) { if ((N%d)==0) { clear(G); SetCoeff(G,N/d,1); SetCoeff(G,0,-1); m=mobius(d); if (m==1) { Num*=G; } else if (m==-1) { Den*=G; } } } F=Num/Den; return F; } long multOrd(const ZZ& p, long m) { long pp = rem(p, m); if (GCD(pp, m) != 1) return 0; long ord = 1; long val = pp; while (val != 1) { ord++; val = MulMod(val, pp, m); } return ord; } #endif int main() { SetSeed(ZZ(0)); long NumContexts = 3; long NumPolys = 6; long n = 2000; Vec context_vec; context_vec.SetLength(NumContexts); for (long i = 0; i < NumContexts; i++) { ZZ p; GenPrime(p, 150 + i*20); context_vec[i] = ZZ_pContext(p); } Vec poly_vec; Vec res_vec; poly_vec.SetLength(NumPolys); res_vec.SetLength(NumPolys); for (long i = 0; i < NumPolys; i++) { context_vec[i % NumContexts].restore(); ZZX f = Cyclotomic(n+i); conv(poly_vec[i], f); } cerr << "START\n"; BasicThreadPool pool(NumPolys); pool.exec_index(NumPolys, [&](long i) { fprintf(stderr, "starting %ld: %s\n", i, CurrentThreadID().c_str()); context_vec[i % NumContexts].restore(); CanZass(res_vec[i], poly_vec[i]); fprintf(stderr, "stopping %ld: %s\n", i, CurrentThreadID().c_str()); }); cerr << "checking results...\n"; for (long i = 0; i < NumPolys; i++) { context_vec[i % NumContexts].restore(); if (res_vec[i].length() == deg(poly_vec[i])/multOrd(ZZ_p::modulus(), n+i)) cerr << i << " GOOD\n"; else cerr << i << " BAD\n"; } } #else #include NTL_CLIENT int main() { cerr << "threads not enabled\n"; } #endif ntl-11.5.1/src/ExceptionTest.cpp0000644417616742025610000000215514064716022020251 0ustar gid-shoupvpug-gid-shoupv #include #include unsigned long exception_counter = 0; NTL_CLIENT int main() { ZZ_p::init(to_ZZ(17)); ZZ_pX P; BuildIrred(P, 10); ZZ_pE::init(P); ZZ_pEX f, g, h; random(f, 20); SetCoeff(f, 20); random(h, 20); g = MinPolyMod(h, f); if (deg(g) < 0) TerminalError("bad ZZ_pEXTest (1)"); if (CompMod(g, h, f) != 0) TerminalError("bad ZZ_pEXTest (2)"); vec_pair_ZZ_pEX_long v; long n = 100; random(f, n); SetCoeff(f, n); double running_counter = 100; bool done = false; while (!done) { done = true; running_counter *= 1.521; exception_counter = running_counter; cerr << "counter = " << exception_counter << "\n"; try { CanZass(v, f, 1); } catch(...) { cerr << "\n**** caught exception -- retry...\n"; done = false; } } exception_counter = 0; g = mul(v); if (f != g) cerr << "oops1\n"; long i; for (i = 0; i < v.length(); i++) if (!DetIrredTest(v[i].a)) TerminalError("bad ZZ_pEXTest (3)"); } ntl-11.5.1/src/BerlekampTestIn0000644417616742025610000001144314064716022017723 0ustar gid-shoupvpug-gid-shoupv267257146016241686964920093290467696047 [49837358131570447864817515087439013768 217790630152030295509630390043323452418 183007752636725657346015922031780246753 262113896575279912339769331241278344279 177558407200939953451023246629148421281 136929296553865076504681539657670073560 192415039389210093994081842103350165598 182557741530928548483637113503078591939 152312715846007778517225522567912229374 61070310616310966143036616435945529275 56882351798282916540663346247514573657 158686522480779859534523214608362876609 85210334586722150186842848782331419132 198362138483259282290069664523891695478 105962174491644106720737449885846770737 249033261315062656917484949663089856785 139280737583202876936726498752829998312 96203889545184151489078136782695324160 208694243930290456762944377328869542824 251198129775817736537493636046342370518 32491172002557837695014870030709955365 157057260026057739908648668261127013585 32158111277873531187646273497929686990 58023085641078573288671168992626772711 203352616803671819759251328642179414361 176832214306605225027954988995962853393 197751743759386172324631466360221889957 250675485398129152936547054273008945084 89802180792752320286820790825168446402 221927328217203245795479583872431482139 181867644367245155189096649430804155534 196573951588049184839338282394294640421 126494998583021765272120647086463689743 174657163006615797502644605616894054311 234672242556809736618320732618464101882 205348109319692361504021855702077801974 201480844443360756410435617763952548343 170821441145829211070253605577359112378 187298115367502536593622759425713052026 201353915199638771306766167529913744292 110056325175807519097151055510442724504 84674679789619373292653213867492283966 168108975031341360548972497299114799167 188785266690312084670451157982206333021 6919124922283999072938889546284835561 95172401022443537916304700401182513359 242656351122617045586289402040975850488 258917690731498966483992090617969273135 255172357998710172667686768952981848252 118175616249074875462815777656446629825 209369380640707258048170718089924020429 216746678547888281943927295868928862244 63169707116329105567261084639495637564 202333112949022656860592608187835800947 80435337513539361770944989701279792581 28559403271199376081807425371890436795 256861001114471080744832531110449193687 38657959213601984487225303100688777103 264329692965823772141881317913001435480 218475193420063453264724104126186468822 55233548185953383662963228863699064965 142847894615807036044593258566061501298 40776137890228920841990607606744773281 207391812963267976992797930441533817374 131427136606359893450088207506169771951 82054365866591169413120690376061966303 254634913083682101845032880368012778683 113001824664061224418685032691163656798 117833438072061069588705088985207648396 198178618302450682247100216569460586289 198381479150163198990715018490680028045 40108560518858431892450501419935817741 249439423887278332139791602557219952471 221966937421423130761062580294130357251 27490538843743647962500092623737267888 199032039511054771408483525115006232955 153374408545054543308974562742599189798 204441596188139879934847569435872573583 72511171850979613061537038035887332270 188055003891843700481760891626319067311 246942866306387063440530450313249487213 154432671448051407822509238106814497392 10269235724501453720265397111909271779 148857768429934113454368585111610769515 108297143766697999083231078069833743328 220532835954576708526395590637539965227 47023132625007027307413233669814369642 84333086497358423101905076861010297068 109923194851260709892302191788390844119 145532132551656120297402397944248638204 213830252095553517168726834522180278894 102749312273606281835206463742368919982 84543296032499431865178411848912028082 255842553711064592614706368471411701728 92792788881700092973313938762496041466 226246741492184645916217086335680308632 47398189106172181220565717959082348717 534841639268407919453412423169225929 227881612330362332482913814220965533258 20468583267376817360819899952174792253 144516395639654137625068920238408162625 23063430578963026866276768667282988723 78622647090193125396541826334521992292 264903205883946296353652606189457860631 73321233545830123884053316326108652224 224457856516455546437636685796583263125 89690091316250629374456315479480007830 187208222107636159370431203716381339929 171228087913280313688978034913595496145 65181480163363913025022929713156523521 260386206624679247021239706748428416618 233532508524755687017145839207222247623 104495928340502321945045270235830859361 142404893002257456916371093923595763470 70547706665310794838360176214164641180 250155930626141180499692089763382633396 173703133121986101552083136940445186732 101381348611023590273882716679386824878 52369949231407573392363550023930927779 164846348231869333212354656533341858054 167611977406913990206167373536253863095 44127887745906175987802 210066388901 458330 677 26 5 2 1] ntl-11.5.1/src/BerlekampTestOut0000644417616742025610000001174314064716022020127 0ustar gid-shoupvpug-gid-shoupv[[[72398276494209883607569001664095082443 117364489934900288813772748912639262763 1] 1] [[194885164668670801306433413055322420208 46460887933725801021646400328802766319 1] 1] [[265214480819444708594123279944559159830 135555755881205794630508718609541287286 44692727376424019667265698780467837920 105348873456947058075098215336964742926 200420383267665008124992677631949344009 175037957226154573788077864523554954164 198784363762937430133582236807030005417 189197625224350476857712002941357479808 123176502074239231605912049355403842408 173219197680757673164794465537096242604 82502246015727196418180291241544180842 252148878141517772614419588889223095499 222861768237293427164610320331139899060 145279042477655847402483626711031219727 87910557872715526777045607382277034643 142072596850302561207634759593757462627 71205756108575268517401216273026274651 12651078513331907405242158198817330707 160266113454553114847517104170780094187 195464879027759626684158522704705329638 176940293918687704807235877854468104601 256684763930845904420213250872082486979 190679352948270926135966349300610845388 180925218261056184334641860647804951138 69890985699528053281337128635751875924 249647620923101369642976296912944075845 105942913538075089762334334130653298694 3898562296566255216819318123346284574 96036249681148056555888770829972641770 116954586547181158405632648906791331155 156714696811280091319378172855548989363 20102049324529059757649901773837738504 242046209169075775000997868731143868307 153110660874477601229072252534180746483 262645300558512784314570152020176734087 170644937290658478142860569172821089079 236324059282643408066541233152180268668 91420241446920934270222801792817823163 221895909267925472012615501139074144107 65585860673582603802310418767748147371 175284970274766593398967509698077212527 264577434882178626916502171362966809724 248619213343209942390691463132907556843 48694357302037897882508173061369838915 7590271812997530261785510569226703355 41579865942640367934632794995077059110 25903764683100553843924000316062727206 208277694495623391365783965784035058862 20574104178269334275866063132729651833 32390265141750340906945023778238315879 48391540618880119406049654232187869232 68678876632229582296123624388982684769 50350996346028914093248748742495458871 104801543658718378265450948780789553345 170541167825831826486226694019149131735 191712035005915681570453205945152435115 171132197785251136981628932361511268322 94274910720002633503096975918879251922 131705134092713179690105683659114095235 39198110458547272415690420119622383324 46934920344877609024617702381518055784 23165921134083299943549996062416170591 28459767746923491203355891737619983167 259003325998562294815931954475285084505 132573405345042766236588923626423134760 125044589325274435507575739483784144221 143842666056873673875855062404427652880 77045649566194835393229740528339656886 230721416549574802093826739521838241759 136984872197606244217262196765704845330 179963548013928826293965633036986606846 81093794490723279885994296550509929282 175340915677491500317276597749413950329 57047311937998596889239670071739911078 78345967891418982524389386889543351652 93400063263712556706184675445068663367 180200784179611435611501496080960686407 135119048356203726778728767376260501672 10486454602716462586191022987435392902 266180484471226163583776411401032555923 177922567296382887995292645607281764774 147354638941110748901071777613832077504 11386236491379506830728620963094661745 42647393401281707520209780845057964211 560012345672962108635101650391927614 135105021891377379180374693260873457591 224760786679278206405412871787773939009 73961499887977539989001000821829880530 201511135175463460025181871183378346942 115951205938373310071143721922524848428 200405446663062724609631010980787818513 4084499686464546462830526469012407101 152724466051124045433884928207554220950 126901627861321624285024729051799564271 242367754280050045324139831677280684141 213094306936169441482299557482247052572 85651902354263777822663401884585899399 107061500515903509923074464269206283499 221594000868361748687063067883562138255 23369088685973206706623693970501448229 225855286644190676337782370996698625468 80297213561030314459788121000041822216 104375640259389070400243588809323828300 189446580253479282905484486251777171917 13339974796188630005869457676998089978 241064276410560038338723364620921385192 76395515368032998743463293241788398517 188914664855694160488405094145717027307 29475305348626328925169323294949894329 118126738456573750249388337944191859619 221689202784680185314494482532119456449 94812282609491148726311465288993793033 152692588155831901280608072033125732355 225123885569700674110694161715400402535 116499445366526195693200909257658932928 62753483122144112754233240781236179858 15444805687749127948434404171151371996 14095553723150444214265207378160628689 47449972008672602110053765929544594603 222342338045680629345204692875855824856 213944253857122075734729482547141604817 37079316985276538985773977257059183254 256448445640796358952644860664830285753 103431768147615597129500944049025666967 1] 1]] ntl-11.5.1/src/CanZassTestIn0000644417616742025610000001144314064716022017363 0ustar gid-shoupvpug-gid-shoupv267257146016241686964920093290467696047 [49837358131570447864817515087439013768 217790630152030295509630390043323452418 183007752636725657346015922031780246753 262113896575279912339769331241278344279 177558407200939953451023246629148421281 136929296553865076504681539657670073560 192415039389210093994081842103350165598 182557741530928548483637113503078591939 152312715846007778517225522567912229374 61070310616310966143036616435945529275 56882351798282916540663346247514573657 158686522480779859534523214608362876609 85210334586722150186842848782331419132 198362138483259282290069664523891695478 105962174491644106720737449885846770737 249033261315062656917484949663089856785 139280737583202876936726498752829998312 96203889545184151489078136782695324160 208694243930290456762944377328869542824 251198129775817736537493636046342370518 32491172002557837695014870030709955365 157057260026057739908648668261127013585 32158111277873531187646273497929686990 58023085641078573288671168992626772711 203352616803671819759251328642179414361 176832214306605225027954988995962853393 197751743759386172324631466360221889957 250675485398129152936547054273008945084 89802180792752320286820790825168446402 221927328217203245795479583872431482139 181867644367245155189096649430804155534 196573951588049184839338282394294640421 126494998583021765272120647086463689743 174657163006615797502644605616894054311 234672242556809736618320732618464101882 205348109319692361504021855702077801974 201480844443360756410435617763952548343 170821441145829211070253605577359112378 187298115367502536593622759425713052026 201353915199638771306766167529913744292 110056325175807519097151055510442724504 84674679789619373292653213867492283966 168108975031341360548972497299114799167 188785266690312084670451157982206333021 6919124922283999072938889546284835561 95172401022443537916304700401182513359 242656351122617045586289402040975850488 258917690731498966483992090617969273135 255172357998710172667686768952981848252 118175616249074875462815777656446629825 209369380640707258048170718089924020429 216746678547888281943927295868928862244 63169707116329105567261084639495637564 202333112949022656860592608187835800947 80435337513539361770944989701279792581 28559403271199376081807425371890436795 256861001114471080744832531110449193687 38657959213601984487225303100688777103 264329692965823772141881317913001435480 218475193420063453264724104126186468822 55233548185953383662963228863699064965 142847894615807036044593258566061501298 40776137890228920841990607606744773281 207391812963267976992797930441533817374 131427136606359893450088207506169771951 82054365866591169413120690376061966303 254634913083682101845032880368012778683 113001824664061224418685032691163656798 117833438072061069588705088985207648396 198178618302450682247100216569460586289 198381479150163198990715018490680028045 40108560518858431892450501419935817741 249439423887278332139791602557219952471 221966937421423130761062580294130357251 27490538843743647962500092623737267888 199032039511054771408483525115006232955 153374408545054543308974562742599189798 204441596188139879934847569435872573583 72511171850979613061537038035887332270 188055003891843700481760891626319067311 246942866306387063440530450313249487213 154432671448051407822509238106814497392 10269235724501453720265397111909271779 148857768429934113454368585111610769515 108297143766697999083231078069833743328 220532835954576708526395590637539965227 47023132625007027307413233669814369642 84333086497358423101905076861010297068 109923194851260709892302191788390844119 145532132551656120297402397944248638204 213830252095553517168726834522180278894 102749312273606281835206463742368919982 84543296032499431865178411848912028082 255842553711064592614706368471411701728 92792788881700092973313938762496041466 226246741492184645916217086335680308632 47398189106172181220565717959082348717 534841639268407919453412423169225929 227881612330362332482913814220965533258 20468583267376817360819899952174792253 144516395639654137625068920238408162625 23063430578963026866276768667282988723 78622647090193125396541826334521992292 264903205883946296353652606189457860631 73321233545830123884053316326108652224 224457856516455546437636685796583263125 89690091316250629374456315479480007830 187208222107636159370431203716381339929 171228087913280313688978034913595496145 65181480163363913025022929713156523521 260386206624679247021239706748428416618 233532508524755687017145839207222247623 104495928340502321945045270235830859361 142404893002257456916371093923595763470 70547706665310794838360176214164641180 250155930626141180499692089763382633396 173703133121986101552083136940445186732 101381348611023590273882716679386824878 52369949231407573392363550023930927779 164846348231869333212354656533341858054 167611977406913990206167373536253863095 44127887745906175987802 210066388901 458330 677 26 5 2 1] ntl-11.5.1/src/CanZassTestOut0000644417616742025610000001174314064716022017567 0ustar gid-shoupvpug-gid-shoupv[[[72398276494209883607569001664095082443 117364489934900288813772748912639262763 1] 1] [[194885164668670801306433413055322420208 46460887933725801021646400328802766319 1] 1] [[265214480819444708594123279944559159830 135555755881205794630508718609541287286 44692727376424019667265698780467837920 105348873456947058075098215336964742926 200420383267665008124992677631949344009 175037957226154573788077864523554954164 198784363762937430133582236807030005417 189197625224350476857712002941357479808 123176502074239231605912049355403842408 173219197680757673164794465537096242604 82502246015727196418180291241544180842 252148878141517772614419588889223095499 222861768237293427164610320331139899060 145279042477655847402483626711031219727 87910557872715526777045607382277034643 142072596850302561207634759593757462627 71205756108575268517401216273026274651 12651078513331907405242158198817330707 160266113454553114847517104170780094187 195464879027759626684158522704705329638 176940293918687704807235877854468104601 256684763930845904420213250872082486979 190679352948270926135966349300610845388 180925218261056184334641860647804951138 69890985699528053281337128635751875924 249647620923101369642976296912944075845 105942913538075089762334334130653298694 3898562296566255216819318123346284574 96036249681148056555888770829972641770 116954586547181158405632648906791331155 156714696811280091319378172855548989363 20102049324529059757649901773837738504 242046209169075775000997868731143868307 153110660874477601229072252534180746483 262645300558512784314570152020176734087 170644937290658478142860569172821089079 236324059282643408066541233152180268668 91420241446920934270222801792817823163 221895909267925472012615501139074144107 65585860673582603802310418767748147371 175284970274766593398967509698077212527 264577434882178626916502171362966809724 248619213343209942390691463132907556843 48694357302037897882508173061369838915 7590271812997530261785510569226703355 41579865942640367934632794995077059110 25903764683100553843924000316062727206 208277694495623391365783965784035058862 20574104178269334275866063132729651833 32390265141750340906945023778238315879 48391540618880119406049654232187869232 68678876632229582296123624388982684769 50350996346028914093248748742495458871 104801543658718378265450948780789553345 170541167825831826486226694019149131735 191712035005915681570453205945152435115 171132197785251136981628932361511268322 94274910720002633503096975918879251922 131705134092713179690105683659114095235 39198110458547272415690420119622383324 46934920344877609024617702381518055784 23165921134083299943549996062416170591 28459767746923491203355891737619983167 259003325998562294815931954475285084505 132573405345042766236588923626423134760 125044589325274435507575739483784144221 143842666056873673875855062404427652880 77045649566194835393229740528339656886 230721416549574802093826739521838241759 136984872197606244217262196765704845330 179963548013928826293965633036986606846 81093794490723279885994296550509929282 175340915677491500317276597749413950329 57047311937998596889239670071739911078 78345967891418982524389386889543351652 93400063263712556706184675445068663367 180200784179611435611501496080960686407 135119048356203726778728767376260501672 10486454602716462586191022987435392902 266180484471226163583776411401032555923 177922567296382887995292645607281764774 147354638941110748901071777613832077504 11386236491379506830728620963094661745 42647393401281707520209780845057964211 560012345672962108635101650391927614 135105021891377379180374693260873457591 224760786679278206405412871787773939009 73961499887977539989001000821829880530 201511135175463460025181871183378346942 115951205938373310071143721922524848428 200405446663062724609631010980787818513 4084499686464546462830526469012407101 152724466051124045433884928207554220950 126901627861321624285024729051799564271 242367754280050045324139831677280684141 213094306936169441482299557482247052572 85651902354263777822663401884585899399 107061500515903509923074464269206283499 221594000868361748687063067883562138255 23369088685973206706623693970501448229 225855286644190676337782370996698625468 80297213561030314459788121000041822216 104375640259389070400243588809323828300 189446580253479282905484486251777171917 13339974796188630005869457676998089978 241064276410560038338723364620921385192 76395515368032998743463293241788398517 188914664855694160488405094145717027307 29475305348626328925169323294949894329 118126738456573750249388337944191859619 221689202784680185314494482532119456449 94812282609491148726311465288993793033 152692588155831901280608072033125732355 225123885569700674110694161715400402535 116499445366526195693200909257658932928 62753483122144112754233240781236179858 15444805687749127948434404171151371996 14095553723150444214265207378160628689 47449972008672602110053765929544594603 222342338045680629345204692875855824856 213944253857122075734729482547141604817 37079316985276538985773977257059183254 256448445640796358952644860664830285753 103431768147615597129500944049025666967 1] 1]] ntl-11.5.1/src/ZZXFacTestIn0000644417616742025610000001442314064716022017127 0ustar gid-shoupvpug-gid-shoupv[ 2757808487144838302895430769948248417729237108863869417509479459915767341323330697211864790593685466362642868685686280572196434680273380283012145961103760692626213505149801403142032630867205290294889677921852958863296316098679545758264555461523658710938789459422476508285713011640130252486568573874403279248369585169539213650618995126951019719642265868631105857663880266888615740687129117228288314207488263153874611799588864 0 0 0 0 0 -216322796837555313021432683645937044292921028613383407157804069297831574640998740656489092120685008467028608331849579265535298919026656996120638521170849310580349430742714282458612690837924997423939358531519250439003103809474194653867052412730011984853274391208927747745495001768576577005852099658803085546514828589578330785402902514368037827033046816681733696103002335485194130317912396254882191766550071245537280 0 0 0 0 0 -461037645433479417894020721333520318742787637796222824861773705209889273869538158383427629416696554307900636877857163108477972707536277062193762789904663727290361284224373517600871057249998734207159849953758589691456457289461969382313561313225919667846650484354465287838669574263259013740628682955721862333944942797610117714349319340424888849377188433375019685712170554798874566289464703683278915239936 0 0 0 0 0 -3006606488311441089896683017688393310181237526393515483185168180454254753097973363635722407434487318654611062408549655477030250215182281891825672566995224009864674440632939039163270907351880438387976862382953630127475285232095605983810246580601204355061953631934206101782233808526261885763004588113518320634896519093555011110157604966440212309535525594054654293518320014613131809110622208 0 0 0 0 0 -21667646451621122746329554641562526144092633323312599411016990419323105385099476066414168972485002571354506235276444763858199439264635997569307854261698326829531703857487029929169587379456251270438809123403197975344780862412222180332148184540879408846734261457232407592147312924337495632438881306066500258566449544033936294138097409605834038606201765458164323353573757812736 0 0 0 0 0 -36008946342647299345277533676465042992542509358162091707911485884063199188678585181307031154064029716715217548592392000646414311357113983560970141370451913098200635822787067067854257570327208938999696955706264073506673179971102683350614122127866850451153062491787093182867397127538003924258331826086311209206145468869911581822662684689775342390081444166762496 0 0 0 0 0 64738333885402706154009400777843384948514403975131509466836736265603889387062685884838924226241494383359395885853573043385536386037715829201209541872597706855188799653603478660006394706968635342978467902539925660331269747297563569373972862258677268612185384308671129076702627081272278586910256050615727493523124564910427355844022903201664598016 0 0 0 0 0 -26515019326962174180142979909852192000598024025005741295940640978614198820508372895246811842900425977352727727321855043342564236181262669572054649107156675328942799346600624572167621155490882477365676272092450671794375283335841074839674104033802419109510303627230113525211458922561813524476132216574712854465367040031027145736192 0 0 0 0 0 7206103572192660713378206441635342218917489717304647992423853713271386261468915707872924405011212678144586363155710573280556474140830016874081726445858124315662916567493737199217110913142452405975457031642733926038866594546019867393529529573884911052196182095293632879922014565430281245217054716156649445034819584 0 0 0 0 0 -1781067445792627012203411699914789751917558964317719007317246424900608235475797721781459407143458070618250900401160717537304193257391576912113861254338589725654811524225989470856639467420913364918958248936121424237401680876071173527822994467656057208698530802400487646077493116544189557449970155520 0 0 0 0 0 257785868023252499546719038629025522238370895088838886132974669167861057091364847664488796999614147085642953811171182098166013025545859882309438475565596820726130902460185426222014793570631782686609398943162320798462220946658785090792728810983258963716578939056822038673472371032064 0 0 0 0 0 -11784090207202014162295386617819122580975749672866993427537075993392758066192465164322165415699997447946113816444451865902475946080059998736123233932142195687596120620775313704725043713670267057116323795251403918781211539279372041111665200731953898028103168618921984 0 0 0 0 0 -516024270178733628499623062311311909026630748206142586718438261050317424310047984113834321775600080026192071968298564681207899012445940514128285818475704941072871032892579017242172498256146144732370397366971600828731748910067376163611390633039626240 0 0 0 0 0 30082639005203703587384390914836066417375929216836277495255127429645641088564854026651642629932602536304239256338883055950342516352052967456427931536708936701164689433642079716822865825451517411212445927909524063734481575283370491904 0 0 0 0 0 -473470234117762253449114353073575227253051133950080887048220406201777923641087656057923908627860421347898111116275922195546977433176120962969045561381814949718893972897291028710748149921273892963880265171252944044032 0 0 0 0 0 1716231160060069630599685050354626175015068955757203109707649882577572773165548338611188714799775273882912731234014004123562719620912869622981185312386637525543829470533595866145631607760885722906624 0 0 0 0 0 29097610765037817861202663659325678575900946766272112229562997159720733072202069362200879071525561150306287386997432893787696445551277644983772558101666007653602762940659581050683392 0 0 0 0 0 -359926316046483943753279829287876608460021803187136100943332906260813526077725113393005907399350257834664287535635450778981949557310768189387775714926393025942781952 0 0 0 0 0 1585164055408008634764541421847990628448201383564778254157208549989039915612818011950714697494640213070044956331618331201033480861222528629063286784 0 0 0 0 0 -2786147914453983786915822775172002754752542153742435684470657396691295332282129004399822009077517014397168296974400680697863864320 0 0 0 0 0 -38152084257499719867416104314045082135545017120806331924723488759543432766463641099223031913762482060169052160 0 0 0 0 0 6156765507729276548165940166182211314235431893392787456381452344509549569751736679901247307776 0 0 0 0 0 -6689833869884920066141475743520535508680559052015304499397212203049103130624 0 0 0 0 0 2000741892753026115892243757690184900091769801141945106432 0 0 0 0 0 -50111580155260460844584241578962989056 0 0 0 0 0 -28293184124737694080 0 0 0 0 0 1 ] ntl-11.5.1/src/ZZXFacTestOut0000644417616742025610000000343714064716022017333 0ustar gid-shoupvpug-gid-shoupv1 [[[-446972 -1000 1] 1] [[-446972 1000 1] 1] [[-33692 -652 1] 1] [[-33692 652 1] 1] [[273892 -1076 1] 1] [[273892 1076 1] 1] [[680548 -1652 1] 1] [[680548 1652 1] 1] [[849892 -1844 1] 1] [[849892 1844 1] 1] [[2052868 -2920 1] 1] [[2052868 2920 1] 1] [[1135150864 -21967184 458796 652 1] 1] [[1135150864 21967184 458796 -652 1] 1] [[75016827664 -294707792 883884 -1076 1] 1] [[75016827664 294707792 883884 1076 1] 1] [[190713877264 0 -868516 0 1] 1] [[190713877264 0 354248 0 1] 1] [[190713877264 0 514268 0 1] 1] [[199783968784 -446972000 1446972 1000 1] 1] [[199783968784 446972000 1446972 -1000 1] 1] [[463145580304 -1124265296 2048556 -1652 1] 1] [[463145580304 1124265296 2048556 1652 1] 1] [[722316411664 -1567200848 2550444 -1844 1] 1] [[722316411664 1567200848 2550444 1844 1] 1] [[4214267025424 -5994374560 6473532 -2920 1] 1] [[4214267025424 5994374560 6473532 2920 1] 1] [[1509082248015679744 -4357134752332032 -98072348436992 295269334272 9137611056 68929344 311776 828 1] 1] [[1509082248015679744 0 208724941108480 0 2515466400 0 62032 0 1] 1] [[1509082248015679744 4357134752332032 -98072348436992 -295269334272 9137611056 -68929344 311776 -828 1] 1] [[8242842673465502834944 -15956454898822379520 -27757983946374272 73664993909760 11779157808 -523091712 100024 1248 1] 1] [[8242842673465502834944 0 86404395953830144 0 503486762592 0 1357456 0 1] 1] [[8242842673465502834944 15956454898822379520 -27757983946374272 -73664993909760 11779157808 523091712 100024 -1248 1] 1] [[24645776912953075323136 -32346413682678568704 122046949888364032 -141608259851520 543658138416 -2284518720 4370272 -3324 1] 1] [[24645776912953075323136 0 -201640765439499008 0 329745118368 0 2308432 0 1] 1] [[24645776912953075323136 32346413682678568704 122046949888364032 141608259851520 543658138416 2284518720 4370272 3324 1] 1]] ntl-11.5.1/src/MoreFacTestIn0000644417616742025610000002022414064716022017332 0ustar gid-shoupvpug-gid-shoupv[ 1 ] 0 [ -1 ] 0 [ 1234567890987654321 ] 0 [ 1 0 ] 1 [ 1 1 ] 1 [ 1 1234567890987654321 ] 1 [ 1234567890987654321 1 ] 1 [ 1 -1234567890987654321 ] 1 [ -1234567890987654321 1 ] 1 [ 1234567890987654321 1234567890987654321 ] 1 [ -1234567890987654321 -1234567890987654321 ] 1 [ 1234500000 6789000000 ] 1 [ 1234500000 -6789000000 ] 1 [ -1234500000 6789000000 ] 1 [ -1234500000 -6789000000 ] 1 [ 1 0 1 ] 1 [ 1 0 -1 ] 2 [ 1 1125899906842624 1267650600228229401496703205376 ] 1 [ 1267650600228229401496703205376 1125899906842624 1 ] 1 [ 1 0 0 ] 2 [ -1 0 0 ] 2 [ 1 2 1 ] 2 [ -9 24 -16 ] 2 [ 1 15716643102160534111758180 61753217600172574271106391194796676956532699228100 ] 2 [ 1 23574964653240801167637270 123506435200345148542212782389593353913065398456200 ] 2 [ 123506435200345148542212782389593353913065398456200 23574964653240801167637270 1 ] 2 [ 1267167468929855903854750250191966490209 0 -61753217600172574271106391194796676956532699228100 ] 2 [ 35597295809230452047 0 -7858321551080267055879090 ] 1 [ 1 1 0 ] 2 [ 35597295809230452047 7858321551080267055879090 0 ] 2 [ 35597295809230452047 7858285953784457825427043 -7858321551080267055879090 ] 2 [ 1 0 279734996817854936178276161872067809674997229 ] 1 [ 279734996817854936178276161872067809674997231 0 279734996817854936178276161872067809674997229 ] 1 [ 348678440100000000000000000000 291733167875766667063796853374976 7979226629761200100000000000000000000 ] 1 [ 120 -720 810 ] 2 [ 1 1 -6 ] 2 [ -1 -1 6 ] 2 [ 5 19 -4 ] 2 [ -5 -19 4 ] 2 [ 42 -1 -1 ] 2 [ -42 1 1 ] 2 [ 1 0 0 0 ] 3 [ 1 -6 12 -8 ] 3 [ -8 12 -6 1 ] 3 [ 955593817727321453093807642925081991552428315714137911219172409259950196321 2910517013546164872066111470835330246421044768278430000000000000000000000000 2954919802742283328413552300000000000000000000000000000000000000000000000000 1000000000000000000000000000000000000000000000000000000000000000000000000000 ] 3 [ 1 1 0 0 ] 3 [ 3 17 21 -9 ] 3 [ 4787767769400 -56802290702175 190362236823900 -125287863234300 ] 3 [ 1 6 11 6 ] 3 [ -6 -11 -6 -1 ] 3 [ 7 48 77 -12 ] 3 [ 219912 657951 -859605 108732 ] 3 [ 41606516273784 76486500495993 -30324946543980 -57977141944800 ] 3 [ 1 2 2 1 ] 2 [ 3 8 0 -1 ] 2 [ 1005406248 -2867492493 797202216 805731303 ] 2 [ 199 -211 55667264366753132299476956212541494125324448571 -59024084328567391533616270155006307841424415319 ] 2 [ 1 6 11 279734996817854936178276161872067809674997236 ] 1 [ 61753217600172574271106391194796676956532699228100 -1 -3813459883974263793031618518285054261914116064020745192095813534545111079038096283794818335829610000 61753217600172574271106391194796676956532699228100 ] 3 [ 1 2 -2 -1 ] 2 [ 1000000 1000001 -1000001 -1000000 ] 2 [ 16 -96 216 -216 81 ] 4 [ -16 96 -216 216 -81 ] 4 [ 1 0 0 0 1 ] 1 [ 2339825252947983196289989414023384155425975650625 0 0 0 1257565912098743428344355615835487157290616629841 ] 1 [ 1 0 0 0 4 ] 2 [ 2339825252947983196289989414023384155425975650625 0 0 0 5030263648394973713377422463341948629162466519364 ] 2 [ 1 0 -2 0 9 ] 1 [ 1606938044258990275541962092341162602522202993782792835301376 0 -1306637247000141812193380534316115641074287420945909743086143932738994282954752 0 2390525899882872924049031898322016641463101073880550463771174655651832418111719646949462291396009 ] 1 [ 4 -28 61 -42 9 ] 4 [ 78251668444685311269707371487528656450521930098767964925231152371415252349959400507672900 34549072257044214828682415315874081146403635560456663308003943263668841080562387370131482083860 3813459883661257119254482986600538873291451020849207247624613697324211759570921656132843895891782081 -34549072257044214828682415315874081146403635560456663308003943263668841080562387370131482083860 78251668444685311269707371487528656450521930098767964925231152371415252349959400507672900 ] 4 [ 16 -48 64 -64 52 -28 12 -4 ] 5 [ 27648 -857088 11887488 -97206208 519469068 -1897564792 4798209187 -8242846327 8864358367 -3955897247 -3955897247 8864358367 -8242846327 4798209187 -1897564792 519469068 -97206208 11887488 -857088 27648 ] 19 [ -24016 -32548 0 211584 284066 0 -53325 307600 384808 469800 0 228140 266152 630450 0 21964 0 436050 ] 2 [ -190188 -247212 0 0 -376854 -489846 309744 0 0 -264247 133825 -90985 -118265 208008 0 601324 0 148180 ] 1 [ -190188 -247212 0 0 -376854 -489846 309744 0 0 -264247 133825 -90985 -118265 208008 0 601324 0 148180 203796 0 50220 ] 2 [ -23 0 70 0 -242 0 284 0 -309 0 301 0 -272 0 249 0 -189 0 177 0 -149 0 129 0 -116 0 108 0 -104 0 97 0 -75 0 7 0 -41 0 -110 0 51 0 19 0 -34 0 -11 0 115 0 -103 0 134 0 -135 0 134 0 -132 0 131 0 -141 0 156 0 -144 0 230 0 -220 0 255 0 -284 0 260 0 -181 0 53 0 -15 ] 3 [ -23 140883096 -45 275640840 -7 42877464 22 -134757744 -10 61253520 -9 55128168 22 -134757744 15 -91880280 ] 2 [ 1 0 -200000000000136 0 27200000000006477 0 -1295200000000142048 0 28382400000001519810 0 -302666800000007595088 0 1490635200000015464098 0 -2790152800000013050016 0 1119368000000013996989 0 -9245000000005596840 0 46225 ] 2 [ 1 0 -256 0 -999999999999999999999971968 0 255999999999999999999998270976 0 -28031999999999999999999932845823 0 1729023999999999999999998267416320 0 -67154175999999999999999969586180736 0 1732583423999999999999999635453582848 0 -30413791231999999999999997060769836800 0 364544688127999999999999984700590055424 0 -2939163009023999999999999952829480067072 0 15297677361151999999999999933076097564672 0 -47140106141695999999999999994797371400192 0 66559357747200000000000000178002258296832 0 -2263465590783999999999999325149651795968 0 -193299935657983999999999998732715790696448 0 -627710242062335999999999999173537662238720 0 -1333843567050751999999999999806700064342016 0 -824198872170495999999999999372289757937664 0 1333843567050752 0 824198872170496 ] 2 [ 1 0 -256 0 28032 0 -1729024 0 67154176 0 -1732583424 0 30413791232 0 -364544688128 0 2939163009024 0 -15297677361152 0 47140106141696 0 -66559357747200 0 2263465590784 0 193299935657984 0 627710242062336 0 1333843567050752 0 824198872170496 ] 1 [ 1 0 -456 0 80684 0 -7580440 0 426504758 0 -15173272376 0 348965414828 0 -5222990961896 0 51398572708049 0 -342604051286656 0 1550317051426208 0 -4831933058958336 0 10198629967583488 0 -15932586425303040 0 20876094152884224 0 -13926929280270336 0 316045337296896 ] 2 [ 1 0 0 0 -456 0 0 0 80684 0 0 0 -7580440 0 0 0 426504758 0 0 0 -15173272376 0 0 0 348965414828 0 0 0 -5222990961896 0 0 0 51398572708049 0 0 0 -342604051286656 0 0 0 1550317051426208 0 0 0 -4831933058958336 0 0 0 10198629967583488 0 0 0 -15932586425303040 0 0 0 20876094152884224 0 0 0 -13926929280270336 0 0 0 316045337296896 ] 2 [ -1 0 0 0 208 0 -432 0 -14944 0 63520 0 411752 0 -3169952 0 32544 0 60405744 0 -193237168 0 -153920768 0 2515813476 0 -6391147264 0 789453360 0 36373780048 0 -103370680864 0 114447129888 0 85495132376 0 -537480834720 0 952639088992 0 -815573687440 0 -94716509008 0 1280699815936 0 -1830275916102 0 1280699815936 0 -94716509008 0 -815573687440 0 952639088992 0 -537480834720 0 85495132376 0 114447129888 0 -103370680864 0 36373780048 0 789453360 0 -6391147264 0 2515813476 0 -153920768 0 -193237168 0 60405744 0 32544 0 -3169952 0 411752 0 63520 0 -14944 0 -432 0 208 0 0 0 -1 ] 1 [ 1 0 0 0 -288 0 592 0 27660 0 -115824 0 -1058592 0 7626336 0 8880418 0 -215487264 0 488513248 0 2157251280 0 -13734423844 0 15735635856 0 97082316256 0 -437410264064 0 547254790511 0 1350779531008 0 -7133429310144 0 13591562590752 0 -7381113216744 0 -29077015274080 0 97676724196928 0 -169734262965824 0 200990761577180 0 -169734262965824 0 97676724196928 0 -29077015274080 0 -7381113216744 0 13591562590752 0 -7133429310144 0 1350779531008 0 547254790511 0 -437410264064 0 97082316256 0 15735635856 0 -13734423844 0 2157251280 0 488513248 0 -215487264 0 8880418 0 7626336 0 -1058592 0 -115824 0 27660 0 592 0 -288 0 0 0 1 ] 2 [ 10000000000 0 10000000000 0 4700000000 0 1380000000 0 282000000 0 42200000 0 4740000 0 402000 0 24900 0 1080 0 27 ] 4 [ 1 0 -1 0 -2 0 9 0 -10 0 -20 0 89 0 112 0 -409 0 460 0 918 0 -4072 0 4520 0 9058 0 4171 0 327 0 770 0 871 0 -790 0 -440 0 467 0 300 0 -119 0 -44 0 110 0 20 0 -36 0 10 0 29 0 1 0 -10 0 1 0 2 0 0 0 1 0 2 0 1 ] 2 ntl-11.5.1/src/LLLTestIn0000644417616742025610000000166314064716022016447 0ustar gid-shoupvpug-gid-shoupv[[927267 -895605 -866862 -733022 647694 -555086 970641 524600 582869 890322] [-749289 -533762 -754674 -564542 874399 888872 860097 -801459 731651 -920001] [-1008354 -839027 -531044 592717 543848 647360 641018 957632 893065 -813238] [-750708 -783256 -868889 -649872 -807570 579545 840467 -734946 -720279 760893] [648723 -1016200 -587545 -1025537 710862 987663 -1047329 -803105 910327 803227] [-824476 -863571 -978793 -550626 -1000451 -780190 734624 -746905 620723 766901] [-900849 -593349 686359 1031502 832388 835860 -1034307 975079 -541187 -935991] [1015281 -971840 -970316 -851433 848978 -656104 -1044347 1014101 760024 -726970] [674372 -809805 713198 896663 590902 -783974 -651080 627852 1008582 -681953] [617949 -803220 -947289 786228 -540550 635343 -641246 536407 731378 -545576] [-800345 -595182 -795484 -711756 1040656 -709216 -585028 1046975 -555068 -834202] [-855857 -955395 -560560 -784720 810320 906673 657648 865224 -871327 -819494] ] ntl-11.5.1/src/LLLTestOut0000644417616742025610000003652514064716022016655 0ustar gid-shoupvpug-gid-shoupvrank = 10 det = 1 B = [[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] [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 1] [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 1 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 0 0 0 0 0 0] ] U = [[34654477538697060592273730261281361547125354042773753220424839 28642286990591936277350498595925990982433158292923417688624947 -46292844372743573462683566502729081625278709999456220510041506 -46483581193179866866502987050643114999497045917731148961241548 -30819781133464209851049806557946364538588971500372543352093774 55800458369363297482114583398843232983453109850341699695655921 85229498391108473380429143088097764479688244750584949192968451 44215190928961391993560815775038041607000619023229549814555005 -56225191928762141199604234326567899079861735856027790129591349 -2821038261866733485761289760067843518755252876151402111579092 -56600445704851358896081983000177726626583766185875526650047702 0] [-44233997260522469446630760966822805324915027230445793900466469759669698951691849173534141789641880281231629593715630462491 -36559859916000261740784545629542534300396368966718562880888161447225079537906619812511890470709036923023819006565007070077 59089551959891482174305390308903681612869974820305118965879971390764354535195791774074234539014315392027344972399643936881 59333014063258601208900846773024008569829778426598034900594241114874316807176942590203248943103962849505271914727134722286 39339277664920601829814667137981330171852255478171631432913015028631637094451166058502577427743509963087332978102132712013 -71225350891240604745234148163467114628379186495659185673035976466933787742875646533693468838507251113274610193687025645555 -108789445581401845151765240024205495705983252808075763658353787231418340792157910611357034591406063587534375174967882313739 -56437573824080537369952168169996434511863668021220885631961274608555736934676053780501098026581810918251033094164409424562 71767493333928453425105748941069605855746310582760948904765028225255282167945264249214149704451263342227593036109931588710 3600856443670218308994302975953359579968407731026791968117691834796054492519277872560955703914855475043394551433564729451 72246478321798948850577554837322604664167598323834547771479811997403832547905027333681929696255633027929662067742578983231 -2] [125234120541160085842632749926653225634551766876524582006028424843484622194344320904579593839076411029404574664662280 103507306308365590027731941844086431359931849897778184895383663429734212976552474675311287906480625174713280911796070 -167292773232422692290873819302822809788580775243595360607886223586801568934200920219320139539793909807299946571865339 -167982056686068274771198629623975762574405900229864145018321156388563290848293367974047543703500321756056697397808087 -111376320165568563716960194394217204009497051997154016140407042457009356929790310037864769292832069406625894388081734 201651325485357982987177428627741759299902792422495664374922776611537162429093348402370409973362309815950903742012622 308001794667252566229877100719231320739885156000660615371570077973945762030596461023423400653916810871232997557136660 159784563029835496486081864097482073959471110329746088885480563201812998253921876718515499356728955876875677166062989 -203186224798620884720827760514543747892116556820405494415111131126230598240582006841437806531067375712068132709639097 -10194649316046974623147872141714216501808326519648445055647762247398874459348988827542798424154186365421254334752367 -204542314399908507768050204400982686728664993936396150465899930418015991987429643495566957206595889365562455444467236 0] [117406180154362091704893784913336690477979880467536357921992495076718262314767269465800610097261430551877526673389718 97037431965185887559012922676605420319160080674769369497859390855838086773442869902436519430495301700307644470099817 -156835895742912043834505276761716856620216220455948837576689484072169330962930089070645919481870579319266560657936921 -157482094534315194630350944280907639148675019860016386578358064988608494742302353618213409083875091356825096789041568 -104414581695337104199516758593256656150631980061085066179466246604570244774540083398860127033478158546601957820316608 189046816841889857824529919703125611619464894447684183696344378546425154323022711856741408055999939323119404268759879 288749695660499599304687364907411012977880491651500456730556451199679154887314292361559548458418384377876914670459809 149796997111511904474896701860710428924926799189384533547824516206929039299615462035121863019315993952889513336090450 -190485775046834677583737953925886140274939370647060111612422543129207174767287734478778953367518799193141856139551621 -9557417970743614074200161666047379107650857796491658811031063573656186757249092363542271789262571204111436620148956 -191757100300257955899359220207710378426399506731196957340564333479560530939548121099520261804626622451067507554363017 0] [73035797907264384077316534420898282956915523440058269044064282535678431421994628093967682497961029421433604701746016 60364848435842041921117879698021186285922135359173644461033509004761716380394572231043877636205057555599865940090685 -97564155234621410025624133552441192542313207767418081033424528869476009124672806246048273422760088309009090106859677 -97966141265295328644121770542693765239102796551562119163446725510238003071761558904008924488064290659338565068496890 -64954010744968883036471143150709270576924698601509028795560228245970519820743472249545494316271851527539446620380960 117601859559033634910429000337822326308176042912609036185312781464573883941098699959645771741163601648433405334510815 179624823755590045790591952845455863170943141584331059893377778240813361093280915945443353579875938285753970612777449 93185411481466777188891779348289203097498945293920870500561184425467302748245335505487257097601354445268983530933842 -118497003754298087354915781404459045617256582021951448024985932763497472034023641766065231235211080753949336848293425 -5945459144558948732219203680407171785434064224193181813855869279170462463328659377381532461937249106502560576684314 -119287867183815553129800918062743050747458913189589892309216739151776284517086701782854139263494793319089107314952196 0] [22116948787709292451755413138721499937621477015550187399463111658534488617623454723953276983701528060983112260902487883503 18279888762611296054253726594245795436400797306449304779068322746822808728985535458880689650339032888184073615608554247606 -29544709398260946461414597289584781605061386839569616430645469198301621818162658212095774093091114089590446387689367730747 -29666440175613148096203192662539678219828408353830989207759006299227190283963653699949964146180299346173001374982331394381 -19669594505243413030854403906336544072742227946076287665009332770427542418819281578472395975271609929597793052771952543071 35612595189404014827312653100910247613374630671337597217249287386090047934406649015172875467311834692358198989187389340086 54394600207531234648367619575172013285723048867058373569710215719983131117417842202228289979502291925011129071688657031671 28218723318585481974291578652110737060825667769496011305732812951103464900898179952215567584889398988014847614759250794360 -35883665799865709812516319059015872398539390158641006272137020544727087216277289141230835824630860703705756254642536532272 -1800424164415806231290703180738687586416564250163791135791055881961473408487473823233110267368564458618532565323136728831 -36123157754084096828826529108520741951654074068994587072706523674892820260017731262804924516844091386422555031894574423151 1] [22116830653621455269329674626411237231333121413157877260771090397930206762489851361720911243273767451929856187884282420099 18279791123556041909075925908830851637273283657519891437322185361321102197429374012947504573542399361677591327954021371502 -29544551589996855450677963067392157679443869254136780112428394379143628600464138846222444209460236575630890155348516221094 -29666281717143891705467732813339896546766600449693886805102814652828190257890280434650931653681562254063388162197680820711 -19669489443300768597379753476273166132097435607912366511525700482161871454815355005271391361905596831441503184800390074263 35612404970514031549016136713644509491000005266892172786278762489755441637069471908475698692072977516672625660760817076234 54394309667613614734293552419159883065077688642516640977585399882272310759667200151711241849576401159532215686530231917862 28218572592860556325818374992390914765197304496518115725741311657885647833865968211694999732146914273433174919549646744383 -35883474133096111053263329996097477660410794824552359280155328352138246671173363420934053261939427835577472268504909453428 -1800414547742709738055458978930857855143695843843291531147854531034858091518345202288034474984979093416728299123459454532 -36122964808107143226134762730577956091489643889686636199849623829341228699446234605848428967112410571722733085472857110886 1] [-22117023380848843894955719104751852279167260342562341244588102147725396364737486271559605492399277785601823392747228913780 -18279950414618837531655188544852365185646782426105987540363504650824383191861686249521380836424084969138850962998898485395 29544809042775761995817368936080946712630952784433599128802067610816305258634725980815194933097482721350163922600341502889 29666540230685538723626075013853570545506324890393343787760756085260975475088472251726602859990799036817275799602506662984 19669660844267929164645385989468002112503365473200220495440043099758826047967383984559018056033241228116597598658924968576 -35612715298886939004403301768136001873828323263435140242039463785209734933829719734598728561242091983696417681580185647515 -54394783662493448067695136004038168938701712579958850663398255295035974785741328413108159813590100547731798887218500168752 -28218818490988631749969922548235570768825878496731963303347718291272430620287819880244931503557810700026800198748193389337 35883786823579980661651678621121954803899252344219915842875991760372388584339006075992123931085342566207654712588151189674 1800430236649921214222020230653257220323071011803408768411755740005619963761788931207375877012053019259209084139042397341 36123279585525370798189988095931342561802762312080955538308325854210385432477026910734886131837716589106185637551656424490 -1] [-22116877685835941126068449879581093156316879986795531671412000168217514541225745280456471005097220528629797966180975183514 -18279829996171668640949742120910399838099879919574547338299475711813145813260186707165945382249826805516492588696591997373 29544614417519886724816901953107832462425743018308566011804026585174846333167795048305565480828046063653548497688385384853 29666344803530298977494463562348795770610233864730846307314261420540044916775933640669283262407924039189118245372116171405 19669531271158512452686322981022392967127144032423100227199176837691899475722993080263082682695916547821344885330712436262 -35612480701539654614499931031648241565661080952333248717647741863275093121664274944949666893231588209025582316214258320509 -54394425339016952916271602018519968703971602499883549539435640522904050606323006287764747376334638139380788003303543991192 -28218632600642840213799892006870873703561382912197567715772157189133402781631597407814705923821812691958515900204006464272 35883550440559795915562052093985262043386958585867777192193545816411200764645415450152461262139285129456188186138525980991 1800418376387260987382720314694111287225894201886546400181385999479518025757906522437177939966534204299229200706868902782 36123041624856130801420614393353178598187710244588209189547586240441183040056537127889355422639945446034535458974459336466 -1] [153300751389883906614715908684381595158854815019076330345965058748651401702935137858908440184753029760178436175776411 126704669325322889255155789303293256412204062617542426056038953236258878888078642336167657842284239352332104584617386 -204785307133600825926434947310539905959072578028218815433605540749531852825825065706317237736688008547806253849730194 -205629068170192708496023229829517659217250886529629638446491929871144234919221241905465442433196135071898116245497041 -136337233771768195750865800819175426698042373162934615788134775700140045270064573206827216859721165828160770141236872 246844067591877261901801021470632147053267081469760073274846382835180760806891203047811592085222603991006855646882271 377029090378001311022910299866042631109246528636811983342383233064557544085727080326250391921776065889271142719262077 195594407236064424442510470319951889917030725594690088094850130062786363258143173351832535868737612955693003921996835 -248722958240961065994294913864181843189905849244726166540687462459351767490199361396229100579949739182283697568449591 -12479405720685472871472679567692945622700070662844098966857399677574753129862397644704023430096898152822295568524135 -250382965545129219181227396113613345269638584922714186640342543946336771926751766478153625156845831899729315417747166 0] [301145885839173819969703925479551813714060284167821933699853492199176116578711831992112605650315588049932068866510920 248900214369411457257922182414032693208395856920884823652804586240084496340274134344788924927011673597465847882543276 -402282781815934612630097787584272164188824371923361697829784861696748517383064848502033956699176061679884775285097360 -403940276397646163213060821209201385741465514653213934881581120753320425216660197172071260459590844140665355066530515 -267822542713061851602734767163253276833168588548648525325329956594452875903239142834446226474341945519480441271372013 484903529337861454020020797144731410464811339116524622140159263189250033132961385879210654032167035729974891033194678 740640592949588900414058268737287704350900234998920233112817592621562582316034237140851683599274553158342791390570328 384228064756762946206145773822526049238325477857776979702964428605396119140722353068188655960146888718381949083005303 -488594445290871062793246858987640328764845862805397138586352857562752368868285194578505080188543446932519701074818646 -24514698437089807263685819578779252693447679115202653667306007102834836796754613466881439945875757407900806631737462 -491855384102852680467538672897022957290337831412350521756365759325684235785140881811626973421906591392201175156517166 0] [-22117226546116886109763322378844674622546324478431531135520811093364799400159840054921920560371132378642101991444495496654 -18280118332831059537068894499955495779228723067314165021046052970446590296867097673757907471648548586088198965665579492705 29545080439109033006559438795794252035612382706199285879517042079101293622464404015193348065694130279126870635558928144364 29666812745232097070406529987146813886760386808585192821066868530490495570649424591147935348711988942139718240704905610017 19669841528252790593070716736908131779276597652400348575771848510586757775959546738047964468508521533989044678518519608527 -35613042434538279612693088687007121375294759538525284151480712416479855084589328414372756965781242033206739341540434565345 -54395283328773697061562245921178021577369817175915744351482042640890919485397031773763669422211981196377459202217084356977 -28219077706875138457597460806660379260640059631307801018393953494350195313523278187138079380937456827669589568226031170718 35884116449273404444698288136788131834030229653398959030597574377784837675636371229369314291573973612525744122253682274033 1800446775262976035289944018144445300810930029492874702563867024782422136675722395287536367476434895753122371640566089769 36123611411180802892777524434718239367700912623868195289065665696626684802255818207220263750824955164746347612612248556209 -1] ] ntl-11.5.1/src/RRTestIn0000644417616742025610000000623614064716022016350 0ustar gid-shoupvpug-gid-shoupv[[-1007377 -621256 -685733 -1029120 -1011952 540589 -891039 -526851 665990 -628992 -641479 -812282 732497 679539 -941076 649927 586413 761030 821315 995148] [-789365 -622518 987275 -594200 -835589 571387 -995798 -993857 806554 -915946 906504 -680376 -545294 -720939 812630 -900506 -918548 575268 688388 -593592] [550743 1012525 -742758 684636 -819566 -922450 -931004 862846 -1037626 1023813 -844078 525899 -812455 -681704 -628061 -918116 -909821 -644178 827337 -786322] [-564945 -733107 979752 773955 -548908 -642504 -793003 1042300 984860 567651 -627125 -933584 732283 528600 -615886 631186 964459 922892 -843197 774273] [-938526 576037 -864612 653669 -1018155 597732 544943 -894518 -933942 621892 -859594 -942483 -590467 775614 873241 -917781 -1000228 658893 -677585 889401] [1007616 -810354 605966 -530965 870440 672791 677405 -842554 955096 856668 985158 929574 837102 -954192 -772025 -766460 -680720 -794914 -740091 -672270] [852689 -651039 -535517 903809 982092 532512 -682583 -915492 -571826 -811136 -749897 785952 -954046 537266 883213 630761 -902395 -607566 935742 633521] [660404 591376 873522 -1001549 871542 1041954 -537328 -699583 -675351 963615 572679 833723 -832887 -623849 940286 -820470 -783690 663914 -631307 -779979] [672814 -758937 802563 -928035 1047989 620898 931085 879974 655815 1007647 557164 843862 929963 -931350 -1017250 -695547 775528 594474 845613 -1031318] [-793811 -539625 -618683 -958438 -943420 979026 985199 -705064 538218 599551 -635710 848659 -692530 578628 -581393 739362 703204 936610 -828619 -760384] [-828152 -596634 -759545 878054 611482 1028872 553542 -915076 899691 846870 -535336 -591759 693682 -613243 -808226 911793 996273 696763 -837040 -703417] [697478 629327 -594833 924068 842000 775153 675791 -543387 -978721 -575508 598224 760540 783232 849017 -1024693 -570191 583682 735309 -633097 -701871] [-992571 -948854 -911900 -764507 684692 -898657 813746 -635634 744436 854601 998034 -664419 819562 1004955 -780684 -892501 -678615 -799675 -573309 -882355] [-953063 548712 559591 922389 -558574 -967290 -655590 -687331 1047546 711682 -954689 -821640 -786920 786979 762762 603011 593903 -756313 693749 -643021] [-748707 933192 700160 -975435 995281 -646390 -1035167 973363 614204 -967837 -586649 833688 -647661 711361 615899 887422 -534256 -722406 663119 594950] [630840 -726745 991278 -809600 -665945 -660710 -603207 -954200 938302 991768 -650427 789303 905344 -728251 824408 924197 843327 -850701 728323 617049] [-780719 -1036907 -896496 729651 -780826 -554285 -604816 596378 -949904 -579762 -710465 806954 701677 946362 946408 968898 799263 -574346 -968732 635951] [-593706 622808 978139 -741721 -801289 -771952 901691 1034952 -839341 882675 570078 -666109 -794509 -629324 983777 -789268 989966 -988905 -952690 757890] [-954640 -667081 -1017441 -907522 601534 854519 937315 936736 -945500 -587586 -577805 946046 -808901 -529612 -969288 -886033 -569067 -639671 576920 733108] [-758077 585690 732142 -770057 892395 -900234 698793 -910499 -584416 -593236 -549557 -989525 -697743 -676367 1019901 -766922 752620 1037353 812504 761751] ] [947891 538090 995215 -681544 752658 -692090 904199 -892030 -819336 705526 -745006 649281 810836 -727461 612233 -739736 989072 -1028677 -646961 651303] ntl-11.5.1/src/RRTestOut0000644417616742025610000000116114064716022016541 0ustar gid-shoupvpug-gid-shoupv-0.3543709603e127 [0.6342777424 -1.66630001 -0.7490057533 -0.4878568653 -0.2446744714 1.996508497 -1.44462438 1.021627692 -0.4039028959 -0.6198159641 -1.253578169 -0.8264701067 -0.9749456962 1.80856531 -1.155185633 -0.6781996511 1.113882043 -1.103882646 0.6760286159 1.027918795] [0.3262652234e-53 0.7177834915e-53 -0.8482895808e-53 0.195759134e-53 0.6525304468e-53 0.3915182681e-53 0.6525304468e-54 -0.1174554804e-52 -0.5872774021e-53 0.4567713128e-53 0.7830365362e-53 -0.195759134e-53 -0.7830365362e-53 0.195759134e-53 0.6525304468e-54 0.5220243574e-53 0.7177834915e-53 -0.1044048715e-52 0.1305060894e-53 0.4567713128e-53] ntl-11.5.1/src/MatrixTestIn0000644417616742025610000000145214064716022017264 0ustar gid-shoupvpug-gid-shoupv[[927267 -895605 -866862 -733022 647694 -555086 970641 524600 582869 890322] [-749289 -533762 -754674 -564542 874399 888872 860097 -801459 731651 -920001] [-1008354 -839027 -531044 592717 543848 647360 641018 957632 893065 -813238] [-750708 -783256 -868889 -649872 -807570 579545 840467 -734946 -720279 760893] [648723 -1016200 -587545 -1025537 710862 987663 -1047329 -803105 910327 803227] [-824476 -863571 -978793 -550626 -1000451 -780190 734624 -746905 620723 766901] [-900849 -593349 686359 1031502 832388 835860 -1034307 975079 -541187 -935991] [1015281 -971840 -970316 -851433 848978 -656104 -1044347 1014101 760024 -726970] [674372 -809805 713198 896663 590902 -783974 -651080 627852 1008582 -681953] [617949 -803220 -947289 786228 -540550 635343 -641246 536407 731378 -545576] ] [1 0 1 0 1 0 1 0 1 1] ntl-11.5.1/src/MatrixTestOut0000644417616742025610000001702214064716022017465 0ustar gid-shoupvpug-gid-shoupv113200891409702717792163966000355453253167532371751053300095404 [[9509068573319153106464382357375229187086855611933097546 4271842113282984626360758539562365814114171429102170870 -17759702680062972863550010512920362656015043038991243880 41477187861721572946030655775707662755085404597108307160 -5243782742622400377848684512280147647926604264242557316 -57570474516915330032297900074382277948092226082851451198 -39691442023468050071303361769224768064783020685116735498 1368136574325345397683214068314548753685759225204791630 38882325913404281065622952126474660414786444511334629982 21658060525924366067499408569988309603526842936659482904] [16472827960331056248258838159209192114875841064752417973 11055661592473954088842425168207875905160844070216428777 -16560334922191139189855127652632587481364130161107253300 -102245748658385867081609185652450631512925122490140100688 -6927806773133223877423268518425302220467823310751166148 28742921711161354730773870543456692789867725621589693379 14310736605755305933866385638819253964858157392606846769 -16014991501246590459421014324140905882300657048699826879 -81503308043560647324620876343032886277665012480242791525 19194058609377655982717031197566907183658664910378329254] [-109734933934562270503406590168469216229765499568865356641 -79814977936376262987151168741382893862364782954378186677 133626969697143446178706879427077311304614297868917769972 149665059613481916985855546923739615387602354833519713620 41594932401764115975248510994547285258748104347283084044 -114293087661479606464120160022800358925423770750498443543 -131521483304858915292609610805812270795903190662579776593 27868073260247900348789264908353779013914728480966707387 126507466382585557035788800218240658029902198985527596649 -103983285416770288102268920890479984309962375465970108130] [114179091124182582838159635859138807708117275312431988888 72039857186790938018866342099151764006275450407675210704 -135958647564984313864674762976737220386273609465893392876 -137836977113748623086616532582520232134322908706353110508 -39648958505403130424111817393832633444137482306335426792 98771210737273227760225008543985447809800217211255619424 138383817476246957183754907890374698153472269727036432232 -83531568830256521066176037083463270650302126963488770196 -59665850209941010245210238755312622861489834786890672540 104212488172405994217125642352348699856251768748581561844] [111146907229695951696474016292279176346380873649543797504 78969317235163683361563886953576359244786258829455206460 -111284423156656542447821201425798324474500022987488315616 -128864395236737761888784942727936809950578458670337206372 -16132840533073216704190053885210668883271756416346952680 71936575188688673331139096261137395113789612697561557288 128028235167433369167870171440603042287857319552486125624 -41129844043092203151024600561803347120823946971906314680 -69716278056658512473084306613953260253123063966900954104 34043655739979891222203807318846715642905966692040868996] [-48945544119598748666062390519512449564008849843608859415 -34927798213824985216852923656744552110662885021091481427 83872849154007409489147877549998397111409710950909271768 72378117750764994652170299394193193907241706518396524004 39167881720986278038950691657480446660498428518175599392 -81609637303540982160086561536058086094023691612652712665 -66440879526238756393022955803236662628829375990239458479 1111020514420903761458906973190717225987391378209788497 20190606337847249085182187793374022035135207033785218683 -14837054054733076096806488318719796374279547144082285446] [4565965807956488541051226759685506863651410011624760868 3492181881011202418943817267527580110911157147323976900 39461193147298576391825815620320144432845605945305549448 56604265994474462404748264295892220624225863674908427124 -17328413096863500505028926621982940665124422268469920716 -48643771179225048379840010236577072580175169863772980140 -52021419276660697100984251779634298701037261640215712780 -9349417465113435540652912465753929600296084265070495752 38749631289242781437940266166713604911714618202430909116 -18933915915475912601355036112428373924790403131648561896] [-41336383131401391642050443152991618920841425678015082424 -83981921540218745933168166698961730340818141341644355484 119619051324150226809528823887692424873092665569791069844 57359568975642082106242309019095290886689391528980785256 13601689001352389599706696797494222236044903367813347568 -59795682186578959961110105467067404963104249848788910772 -65397723614377571502938854693721405692307224823682592396 42592878104789608838213389518482176731590188510637180208 9920812157887076126172384077761201801497607298814386108 -45132518927593441552501636215301078568022033762084120792] [-49861066123459998006862729910986171295203945428483340835 -35407425167837977411438500961193686418300361423162989791 92357206488938784494418325514759738413689140887758688444 -5657564760989076343828111309403153669939072934734661300 41671230880738697588228732473944374615246021756976674148 -10711124317120463934382132614621248039431313315612206405 -76224317951311690961135035362182609056216309727633080639 2637208115428887814017590413315049349698597330449554141 25858155834234711795118681073700474922768148144251824295 -25990119790243388449513847601985281200137341894872589166] [61623531631064187432686831211234110772009391741788753961 -22095530335186280470348249242411284415648788206132842467 -20711755361024954539607118196944853953156730345410464400 -66746268941133150887857051757708016432030879372710964244 26099945908427902073513340584391341626437984932690918396 50975963872583708863130921554269663855103316623806906743 52201087513253571112258091209051975785803391414176589285 -45191083604629728008798145680113826847397615310533055439 -50146971408392286617891235891675861782320000106664060689 11541953231519243604644211417760923555459588623123390410] ] 113200891409702717792163966000355453253167532371751053300095404 [27249473184013512266407136541118635644159086017541712403 -50584592209942650462069456184321559526502345177792664705 115689488135636337213972690426493653067477248330091983968 46478284530817963216164361200291518714365212127753615988 70661072818371598049922919033409244304109328087891245876 -108305918613468066616370185132973898524229550691366617255 -119229339875612413145903997067198928544279071748882590601 -63796927162833233139985589317687726451218561510888812713 110134329954416532243495157079500276243728345769979945249 -81663651625066088258790377298297690632997722240667516882] [113200891409702717792163966000355453253167532371751053300095404 53416187193543401439887430820819294205975695546488797425 -123607612902745582703514051875473670204659819545865 -68402251288605920205399779446887509578119997 -40944447194334612294903085651515816465 -15153544924233995088343823419092 -22979394554373573500894590 -8722575497586664894 -6104870715982 413939 1] [[56600445704851358896081983000177726626583766185875526650047702 0 0 0 0 0 0 0 0 0] [11465750313487428661702512911842922520691216342563125571848443 2 0 0 0 0 0 0 0 0] [55231767316270678911483408554295434801191847687452448852191136 1 1 0 0 0 0 0 0 0] [37908835104003064912155774912601500340365754030028784231954718 0 0 1 0 0 0 0 0 0] [48615901178068930937993265623819971877392545512335892026898174 0 0 0 1 0 0 0 0 0] [51840818598597540130642998688588606375873071993964789114593617 1 0 0 0 1 0 0 0 0] [55361570761366016585700727191488280019398548582423308017837536 0 0 0 0 0 1 0 0 0] [36090811750869350784108074019471312745428867031617225757665622 0 0 0 0 0 0 1 0 0] [19232281111318501488032229905889533180588029146643536978782361 1 0 0 0 0 0 0 1 0] [42496144125982001757158835167287232900763450071403701240310105 1 0 0 0 0 0 0 0 1] ]ntl-11.5.1/src/CharPolyTestIn0000644417616742025610000000232014064716022017534 0ustar gid-shoupvpug-gid-shoupv[0394820 309072154 109014622 1426290 175222167 825171846 88106125 543013 726393158 718508011 224282105 670970394 84911920 856082243 51432313 356689413 487830678 743695336 929502 439479925 136123276 707988349 831373101 66679668 746727 540936511 114305132 82147118 380194841 79736700 862619239 676125089 510124380 35667584 474394435 720924125 724948 222793534 105330644 871564016 68412077 165794770 279048705 126777275 17627 174553324 851984080 873153773 495650905 188357106 289635478 760525082 90604 467949471 828574359 866977171 812328920 825671785 9758 640977503 35747401 791343 602111985 393648] [560394820 309072154 109014622 281426290 175222167 825171846 88106125 595543013 726393158 718508011 224282105 670970394 784911920 856082243 51432313 356689413 487830678 743695336 630929502 439479925 136123276 707988349 831373101 66679668 182746727 540936511 114305132 82147118 380194841 79736700 862619239 676125089 510124380 35667584 474394435 720924125 338724948 222793534 105330644 871564016 68412077 165794770 279048705 126777275 73317627 174553324 851984080 873153773 495650905 188357106 289635478 760525082 63690604 467949471 828574359 866977171 812328920 825671785 368289758 640977503 35747401 791340303 602111985 393652348 1] ntl-11.5.1/src/CharPolyTestOut0000644417616742025610000015530614064716022017752 0ustar gid-shoupvpug-gid-shoupv[190508694806967015998600611097132060049717118365016280475020799440937327406646942789463171342229692206347643711656823487561893705323611973115765000429375831263108569315225427694150247540246831153992507299992825439755817111538589609613023922678205180207300350411328634748456398347317769763113112532949991488988450573239123152557436015405152850660488623917857833818683001387193609953938476094742107938276333134954685460879041352353213523705745901290368321559046533980676310568693475940388053682248147969674444106923575773142801027102175343542579052985992474969967454917969163643940460819332006220647042696260091357235019028610323559379428816498125971469436220619879921223810882259943059156398587216631554149611899809727132305526391913730249737864692929996282208822321711506302712970006968799992644118563580707422065774467792905866650907789662026726695059010485690597774061864567960192738380217011200884878157520759920017356366290889818183668529815140973598202522753939144473600027992971354118778520924921276625945271355017006545810816893146727901309540633127638217572327583960024077147518348286178124206625881051474510793410494138927402297512333148160000000 5510370375206376125805735185537274993180811627757919519755287408102657543105514120792053265823597303123658199603190909569821147417926587591837948891619607615404159338429979309010981827777265483023527116617038416675735836718068782894703173068052932387089155053446282556998354357342954371353946291827882920830186259111039667082687772480659627704424961644441004621954251872383257999920305246693623623498482718299450630387944250424028179677314085650306231332277967061921960251729426061804857726399930059931907366410943776901370704889872998997777631140261117929980793431899765308093602311276420817885590340576896739344657734289639054912398163280271557909299828203587370332167866138589662124644838451869911270013194124015287901127671853661852442880293741916634440272968369900740132355610706928640899686635103468378085757505718584806093099415444501421862714784284070333433948596923713685684574641540702890150015865159237374688805375049432465077932740662557791642851660645069380471195882146186453681686664702908783838072092969407751326548494273380663918625448882464696110955357483705033360786105019870179686630400090123377232360917098071205836248722702336 76636285697827388747309150397897338703479382655435292390554714660407941511174746464243025647528622769737495338417763000019752933198203429069288208786893348291060629771936723001636718081554593978950514639343299849165764060314063003740717219445956162206615008145807100960233499022750960786803534436409840076666609990348072618173778799055867435553418661212328637044438515447861390096923942145452184550926103620714191992966658028523149438488617327736796164690205303611559851533348391220497893652311305086830636423146920281968022984997613739234215642701976964164397239787490393250734733620138901318869290768097670428843847479492870130488315826039236794818526738146932716621531032665547834525578389396835279873989042511968000540704297800489965929294381610645655637781300868741853833969598348341278121723340700947141766103901608611245230634594534138275745968582584616004535088835018595756746851357210313362093691247845116569117168912286575004344006357633865556011340608321685351516589956019986482228918514350139373609635120134296139491552111152715937110193382344029831207490105756020517515406659981844923071514299766843216132915342254701398327296 682967003344890835104695900793461228916913282023162349416019476885347047156759153830343120041870425125569604438946978617346346223802843129244409026989530580448709099715921025449151356852730096275479574615719078213208988161876991217023296146618565394073289073124848475354819462769506785090935269931460083937050792647715752262044025073338413934921518433111330878769086105978574924684859970370731689106411068075813771466717648400417984385910546076246317409340120988390231835922623872949359375373395547861053095973616176322399894174273765908103222264211747808396140882054612886289413912925004315543450775343461823364610689104041918562764276178075501439400697622053625550952618137968427279232226138077885052216249165524377571639876002893437253703273718596321975206629081443850727596346094491858960684321942142381936301394414333513107590064735382496422091136268562587050129410391248793338093640930328696656251923097684767440301807638687503824842067179628362144610969716679671925283856807610141684043053481248490183832573811408991949667380869760117396637297998369355376561865448872187244433527686282937515305111719666762008504477296919552 4396287874266350268417177805786841295493285845771288614320531722181450577440496198267540620122441281553812907400504909524660352843872107689903998501003247215720798299930569761579252919847263597017778263780200759304776124632551896764004200319773966307706700837585719362472911584420160829320074823113112187068424639830701017474825263597859572552083301841676783056997824812281207005222515987398155599961381284956593211460558976826936242990196571756335894460511674105502282700984315091337756595274747455563525695047962064436078517466962488134179515600566425940659015475067087631091550405699107099365563958969655433429595966567972539232512595888850734247448002102630529844063167928403354823170988961018692168827249173766875055077986870320850147504036659688993124424941419462548993704935179215624593583416622387732393558335009285828678194876074307762996487949549217902665276840258170080597450696368401354134918695158808862725965698566836610154549833757914692891695902811629791088761009326218529170961543557487512210617065814711103170567820807023070096232258273723831311098314998089425172517665091602134431378731762129472035179249 21975839272414395140361539785289148168737851601427458106777755540491334819163322484647244978641576412004122655167427242365378926150687855704244197490363755992292471167821947596597285923459298708017342763275484040196472357872457323212426003258309692000740218485926878522772170127883562943966756258953435551301344298636848316395708197448952847533805085919981476788000303763063749547614198262442705566581963433679537784550150274110413247581659422808793927285653952739466893622437618071127017592576972854442335113267274667707244651098414183394666701084263995550246669025925884806103308866095793683394213988768560031805699567081080363316032748368087823642161357731024813134467363964793281047599734182925994046660369640730321168593303294139003203933511829270132988039147532396132671420753632126315580576038889456326274419565551013232046578798578618873797907261992571005987755213987784888628036003990588206548067335221448237972961862770839037675891152426688093187411493332273636238909511476593797282376050324676361977699816044607823657737979943629751365692194020511409834121987811331317079116625509824147947161648994117662 90614572248167832815398901237692019368525145085533138287685444807567873204605246604398275364599214250950175235171627805701057597182975632869431126594165858643501966801330401701884178826293853784654266932084418159299910396757430868083130186649756193170672642494752192628065980129443480078681559872292550125041244266137297279861048796846169326664796602071039267580150457326682548667162241050100846792062281616565917920117176525496157042264079387008296747997513691112950993064961357912157542541361239544658084051215442219429376780912474018936426931476238924451921866695962822487292868699840533224902464369267076667572591038734279554702463167517642637118155796167154515207970256621250915178345320909915299152054879019436390822689493822916282165358794664029287244374521577173641509213361383304713851144993302120088461588930231691757002754227719102412898327883927285380172840945990247971689534806358922800882578508024879529511841393273052597976594405438110148788980182813122865554195573932864901904909286094707181763733741079778836930551780931164321209391340730494169796298921330443829194579510911833655576601377 328970398417249875437738673791810670683647177007669554639061977661129100259388636124853047280349180968995650521486117611261304774855877172118818503217976563637794662123745036086469964386605974339488969452314068670779496333555667260276057696519162720936386665699718862715372641593041230458364666891030299116596377056920968571888893465794425500091218841221526095522810974059764947932904726898749021756246707937422584947654173499250106585907320417442000646966083556296607788743563855449319383344414945991420349690655656572763836066709064607426306646832925531075519272224784344606184131358705975839652153843794680601129001228882668623998957850199335696114626372129092315495250157484480620506477204266405136218111512712589632928130561672876426318364373974128796119771175230813968549877506567434438125790847566327516518294857166955570644984229507908647723196006884389541854025643867101067179678490320518453668197131386782690931516841798901968731850277321174688014066857404664758976402868866557275703580522731564202058255775248697080239282936435654805413030583016332080024310102484631101698158062067490199 1127579186957279465567668413182166261397126766366319885142562182868033829423390009947792480046827709615996364865149656955177256175360655982981652377844755656703086872891547668751079735240226870806580504325683552641781613734598976127577230632147939492768120951488677479596772843739320350792156288111647654894320229252992971612171484642080125139314340876334784023575117675940955402037348660795174532129778527784638963525831806417148407590099717948311458840122301529476398574966897559165380798926543906149343707861656819996067396890665167537769521520650155177445335334404782275667914595436068084005414865156078561007411769443544001978569847632042119527015851991803584322700647043343678885335970712148283137252705043154445174772568964759581374098650514877175166730024379788369366185937637692589623967096975465827342905551004697669216024080226292024812174472626656605850289484314826519488201803952735942230029839337765567769407453010191965826318974242809590315145991767303399763633467299753793823335835788081811850780569472659902942011532595431085475913394407208321374000736048501106892346552196 3828041097219390857907082551067745839476775728326108881879204364051036739270222883898243519649048587642069576968281141303097991041018521880872948859074212972982480449636159997684984126299406495337515903672735412353899285441049046431315131720847467461635427950759940265793408225958463477923656798926652172053707784414886859466167575187298829948847616648829314671347189690358265482551663036686190713893382929400857167710163163729354824015596295132972609948785664123113633400305046225801228443620327395362882461723640091710316379011210504884717075728724641838344258079857344943803769697097560745957594234550289137121341427605700174589001506374718509179023501502389872884093440923152550892501817583961673278241805137409553957313416749430122047354932415388574412196293616806554972921398129524769926234010626224067096643334001194753251645415328660304032278529100608261378305772515847975694249308640869899779642831560727309583425352906457046981218535153118614520625245105811319924139353834363134046379556619709601106013471271498116343693680126950788286778727880803528173998527018709543211 12846134731688678874091515609227180027437690702746448213342751690753878562510042778660573488767873354769669317691187032722535030135303209764786747127868178272363478080136747815943752727880681013530676352679956461180005064025710332201101730891353638781103510027299392807972101297674408887762189593699894895525116998295886036859208784764517719293702188737006741979158231258249397710045725785608974164198068415408769382390899720139267750604996537552615497472442675629598714235521235200473357114765795449976837706509938246497769234249256837375183387716855184063918654748134789245470766987274600625684341809777905089658552539780640596719377160142093793100935591877956074240688187266602111532044043715224141229435638253334136063649115123041470933430553962665790743567847484538982628767295204492897880624550871686675533193752156303545638905826964767986887275149742469089443969949848597046642581030974447859327066316039701202403271834352137565019594158277845648681602629364580908320567325004601703035295876317848269027005261020499575466287921842640599487183076541840358945569793753 41046983192534522533335169525136765306600811060513966258767005515620968135643738818842371156102573321691144163061313175735289972587684800501673555777397097134195735202271088503178235858188882262649966998998275202228701215157055999496646719386034958002307593053418734615992027304115386834015123932695277057767984414997298159383099033467257898944764425338679791490906981961439153570377071417385946693210021092344133437630368644045821396458359968401212847680583808841391739885911779092086333396344701573836116255224700123293901585505971177624372765972351113536305140808608187662657753313060455900360496358254508194457882151721477763003798366482721585236424452141686305834178064765615407864281847488216470092971242615404371740176055518815045280121719735735059110329913104888812448649958627902271186994444227106172584304733521997451563549006785596680059304971930918971009039321422587031126996437792329230683473369797165351134164090806234697826881327259320681155748181192685414938903208953111115066829305023346231045250552876545675345461882235720979123913883979127988276 120369962019205430978689855404124372900212866215205222090358103895296148759231283753806402533034855572533338321434922099149748684298577825503701909946986150956281910695782020429702123379243351854028821131399252666599392432737132350839146686531554935267725091513381349351580172040351650497931963524146888590733767996958117308106252499763150598507713880560527810362266122786934877928749238115161454112628523538128520755120190021061256052736063390560151830042273317211547890404880184101664658895849948400163661998484100081456221309297572839442948890490150388950696172232131277679766687139834183139867099921122832197907908704608609633735919558382436288880044543333475800536136548586775667302671905517449576956106304601772228184771059609741256642232027139529888618405957065145938709716970881425409138086093981132615138744117012266121299183849581741411838861370187737459710513819502849521366609082597000809326957480876650619264281372978374209662648437206201048779834875669900827395300764841978960389991164340598542920725526398768753169985590889374335926101687132 317390868282092512891464159675406335576019420847475400634608645062826040654058734124506912818537056545680509611337511961726525747794642469756898737520592378000699701527041763678373366705001530040418950720376667599563076056319177069208904205784897373553098400914043787719673249113833234104384140216539976216768156998966282134713978459662799222559304232484057407495764809394124534082232804034009824219659054459163496283843498363231386225782200151257443027821289142021696055027740906917259641134142410147082043581149683419536913715176895243754905296910385301950887106149817372861377425734209581178617134139131298654961272698290194979185991461943128575413334064152617241077546842897682343096444192163319882020087557959980674925732863827537642715815108799502024302456279843243886904130287868777656227533467734880375316555864413697218999377364829108910069903340205165650328282705764500301481604737256903378796730728725738484527988676341816454744103887175989280705236795599534469956241089552933313845021568007821694409715810476520818750680515460794538701 747434245949570578181292635933035612072425856921900130057009004535428379144294535890529282308866690434029416449462106518118891815528994087749187724165985386180766935349891861990225450975205044879827016279791936496889423120682367069304178872753667685540685718210843403271559230208965801434195430782360915502656776511706673003940873844377653500618983242456154260750622937180099955007684065048805422469220861226201819945087982634678888815225200547750765376191063482272608383516266927895863769579892065256681776776572607399582887640357212125973987543818748772546033474374828025683421617731569870956841430428988314092633981559350133569702272073683016627343537428688065365050085741641035677907679956032228224919385238963916553657262288136056541558536871478861223374976391048721949942648127124373533717817331484205349704512261697486979839580483756001358055941617723657425578852084665416464178580793318854279381654927677862383599569513100273095147087971352329954986495290824735159974762698434222178803981416011999330180898763302215807446645423983 1573229387044305762810701712960729806419837957062370675243187252889663508622635279953927201928481514186795665445703580725453464896674494229451296953752915279032258877704866380340656463330520225616557456362548916196929799891892939772491827777453482562995342293736577079863986180605068401866298479779951383867420467993942838063897717911961821242956547279511050042672908226217000401726508158194050684966961607206726228989042465822012481387201661227837635268948627897540445353051617121609658117398950656618967708231227442021101460677583873814833561706174003930314667347819267409588490340674599298128875223335443745067282564160542254444421736070817445584293683064060596294818747936486825660644905498015073939646049793417694917491899903088730811553545967648558153695639996912855671927517014516169567623565359911684776740577788830188215200997801446988405027198937187633031620559718587346141186856087602712710548464323333040387186221593117079091042739689414270471754094931230742220271128440198059933290551778609649137642021409839835341117 2971907874675964671549636163311641138310784433581148857853989601197878243731153926191585920286210240130308181456314268777322887415707926752080313459518110385217099240288158920263313325284336482127032025866771153285721022236451893939337014509262983910116826065775258635967014804317466816241384669549178927805279837501266231783657632891911127980109553588901411240837224400758511748392930847870735759326294342860382213024404028808907082527919031793722454809035760904952040923541964548596397340536258852957923155006371208146939429957624594302691761080706402850196228052759672118684904575716923793865730777153497856557961915829536328784403195772125830995123543908831466409358326169617941315992792564523264795831787202945636171067425470986790499829208375227813497076628392374801256264013219847847492774280076711106157324861107587295447266262535339803381463965965567208942794446472646092479605887460884514525603020644973495711195391739803904863141835870139423068816249402847149849395676670827796577644471864843685875165512391560 5064909821165357427740898821451717695483108055661974648346952768086282713713977991223493769601282271687750969761106676324260369644937032721172647834053411318725230177794233414878578502338928635450773150648010274070822103872546340665820085840711611080101278821956202037290314619675514536838593067968292001669775958569667922188650775102898556223591120275182422470313223835900425198096918487898549701704968967220783964416498254761892847800809763841421585873530760927316572987006194345563486682545779693160483714677369544956000884966556507240737854220505337650937686902505200189197828056978701045101687081732223340117606938652988648936811684039194952857066228342412257685593198323699130618153473894239914572395221201296926905398262390985858080585938637932008742052196055693165012994572610160964714816378353854598776509896517550182301163413897772666255855095700964690826847498917941863456414161978632212826501333782135308398129733934965894915286694551486779552821180265732291733685086379205605191722998192110957403956 7828767009830700810388369063141949193420751739123318377350285208094444722839264691835113093683409279394949645185739005030906169030574921283791443596713367509939556017213885179560203881438566815434500182048823743283565445493587354351422037110268635787310017932175291423325892602135674703135362540541144218470209056419495913201930453347722254458068899007384878064501018319521751379289455429554535297973498236575176125054965632206281397848261712959523930365695279750709452415208308787835689489622345848219917675523136827822736522266753451186354365896484744861090836536726383646816188698383194003119464375915713644409725671105610925074762108160249835887512288062278145924382470580379804107140678433878773988384631708991519625587839063383419702854416884968909873970835677056393967804133890679337444480944086237950264371000505596585858499722997817806488955630844451588439580569708408393267601197550129600466932017502547950688881193144529246904777212900147052561850901135573398893616614699741101556383957623950 11027953267970630909581668660180702525710166604151574536502753399243127761293423114309112958488322904185983630490091220267741942170658761332386880130095095125454650258548732386949971262756160799788021777165408980659842648391794646086289598388046259464106068726431666480099215700127335686498548360567464330941830674129636791458860061050735620157440243918265288400504675977112486836207180247649786719533244850209726594494136352246399581221659532993631182557778926663600571479225800466743290189697181244525247031633354445948798654874558656880756208532232459180636883494595773559367258215888851553181102434280048138396322523918175525076990189255053378524235643013682609382833799813511022259200406106460958595849240623546953821707886505604197670807955128967476318436911542336553838732957091404606373712245908845082101961130007946949779338071620201378912417794748209692121465900173950168225648981276821997095473570661279993984450045156764233849452643862629607472731563542306471474302903443075714153251 14215486739027793420511165578454333171006241012338248278469606836641329694572118755154901761978190884111496362048095252966437617057161427406418816792709322460071529668593343197811895530152598553015381739667361824459870247720392325637964754930578154018241965363055967450169545586365546219350652302155348965159555621306871674496658449554070146439545286362289367632698431493166454093445340646511612334716195370512972747468588052163179510556106635160442750086203472053538549820142810860107094525701425913909439615499351035570540082895206847289472896654925023941294491351446694497959815443728727224324009034933737141512611116982444023575965025569408040259517538518590287903358851325480448948694520552199855814106858663947641612058623218782306271114793408923480312872755079110435546043520071063500723171656595429586296939369269064327899133290007363581662742491263636752135839628283615863673769087375503322975245350538096932985710004443787649203391804337656263776622567064736118244226973732102 16823213050615015574645995568954608900085789946415305967508645386810651530859610615616065900491935732108453200213727440212537069375711049806987407713976168906257897070162390521380099327284203646295831293800491535187702914650760875363281304319242813664884593086310791131029907755466417107264334129010572630304016513361342822611282389107467500492755313172690180294445757762601765851880161139661911942723832227015286754312110734894658235311290551881596546300232232079232112114203573243135529880770787769913441089596103299142135915478475807247938476721497374188525122484544188275396283889844535908320063459104525992961463986469133777633535151047812609187809171537464310826950489706486797722376935833050972156979834740358479035954635888238476246604558901239468585910262135004843451090056166810578799027304901579232798943645535248751413210862177964683750846679825599666126740068794727853373287568397275636482248940484195325918840105297298791284502764192171305684162491259529294673653 18320954461901719402603881313562377009401564547713869109606557402074913521520028052788231923042514752745365775977756102190024949830669781722226496457109336250918951619631113429495852595356739934223979784237958546063667407239316847406400854775481648161563380355501444518532682739440365957587538600264296062117645644496737763187940459929800354249562128637860956916219185440983067440511552333783961284247296332060225807120263868674689623688202286085250770772180092240965739044775498517677653674904084786480993044150365531892242656479038825840258257582394728294862433919812255124288857642814411260282234577545060045419677540238369142509478100014485181889715257019476786439121653908732334795199955735307484547356690458781965908744111000778635472303977725195451882719671045625635428640265745857452393288397994010335302724673974385975073182607618018347668468015370511487270543931601712325029537566884360257779823415403804835859406640065660402203302748500590476889654999464613 18385409832950842292089035324351512946826899541269027991837745030955087696606749499554272676240449719060302191374052313012228961211752592255454040803253928737727726936738557984533221126391304275252334846056219712825233396747961359388338667513684412893161471645863262625410801307258312354903026026916430547856903134400335537137322446299948000342910844080533731788372820688170314786054744569161064441938902823400044989834933543439709133316097990286158636499639698957989569897897124383299162476831249495725232812811854339884924944100062192642534375633185637177022263691127953716409675384018660772111790985733846554401935712519249677941862429341976348310688964181380802623013366514696908719963693895760771545029990937073407162270288935484888991334762556171132161513633483740446380732870015294065952020155266360129415940086393164737698848690808153653487667453028081404166887086250867887652949032793797062823425710167149144354011998616185500232294021330847431632410 17008368686579424815117496574809293086074091906200875734261281730368169164195677739766001360143768714784473902151810175411370635081445571404597299311781474000733427923317658126082790270740349416026378289196380418656876582825319625475320334244109049019451781381757740864569470806856406275621080946305670591307306547075555171887105833184718962111267685090470855597150670173338533858819359847058438281289423534012711457290519652603986913369081957608105566157957669255030315498607014574209543801014131332350946295450349277969967349865892774454263245568238179693220751733142631728467679344802120247528751504448876276152614430717161456971333106897257575781667430646516639116334471151927273284783410666849755608697720558583918495399810421101111906614668099978333887197260202329116346757235004274794176212046262703347146126953621416572973980481108294531192965065010744898054719398893718784524278177908301700443673056846445287329606464105566315392002815069485 14497357221394085077679237312382517578002131539538402880910299082998787709042282643500220112505747809065216942735684464616997436596456210707171052151784415284352187935359785690436471162612776127363308998022463935122728340083040297531001084255157199129246945105927264346962922853326392527116403492287489688967222443842522365269884180589847605493628438243304413060992524883279591916116066671251664293319928981990900420136274181830012817405939932318234246069976826210875774808355838848388505435874539066897840423165045159463734219064931537037265114304080824736247495960867958491212146793572355849601409543553437250406324206796721546889918077010261300607244788558933370878687400568722382690322971223165957096828081578491778577327999810476622354466437474110184276347443188730954255334078129098694864340233712442930823399200090719099929536740930334720676398853202875442324468926705209405408751029421831194880226547414912038750111502298256090787705 11369205940614014000511209341577104029139488813173928331165498102870062495615440412257343209295222692145740554547698411460718303239702377282132942984199801799048218477384755039954678522458399884694232182445364912027847114296811679348753838355473877576486648933425751325474378559329111296939828399878140649232150509379939212677131781032777176621493759781596708530888631687056736526355368016552676962231642953990908159704289702837351384595540574238088840254312196958632615287990872838099525132185584492653092229927581707431087835167658843829150031565608952061507519076993785076894776269923554651122387223532126518498109540321249751015323838004828985545179954344807681348589906471132409371576933969260625224070366669064689270369805478575119218070905111170095895365973741280569798649044505099063614867202572623694159831195823552529727198410671569056999383625843172119910889677028868744020860940676245854774959414866894188679675540644808 8184062434084091394962964843593603316635093530124292322517090443544531236393298689685854309670172660565195086967622398146628199959805961989300832190913900545951427121390544583722608062709704546689438940255432472297411829811994559208033004406483896540829932788946481933639848337863109713945483367335781335446931451625787771255071554306486025140044088404264862605362224110340698078767469783017133610874638771519302470345725128541447838809207062900290887964987309476327566189512266756113277905755207677892498922391151701604013059740001819713839827782451813907298281741186538488709114921032319443156997145350082754502785876921286166903106119125028253825880919239580124639103680943342932647665075820573240134269153059065639476637714675717376761411995139839244376239097568049127858577704968915499546972617299408212797077429745039519482273112174563321383380927156073675624553783074335045777880227373810704280398098443462711993836 5389665418118209000150519862758619702702796716527799183600217088520085003361602674992050943645314440105358346422312246816067105629738926364766520405849742807008110767254147665307597187958527051701200399865105214953893098414205292010616649329263312571541320981727215265893721318130542296957693112538916687699081307013502135884389833463076038609849713484163551834819122712718864775957427327052042642814585212056970675632794405380133936940619450338630092411739268407371099262951149642545583595282475626616290120777761678216367683507644309481321145955426684522604512781010945370392583330116177300449116818932610304255222506528552743766566836759151866937469480186772134336875955173266552776403672329112371317331509117947821249203157603581222864165325076403875057916007597248467667028651028975273998568213379299277468391054995596096089292454364381624186969883639445634841936025267327493697865842458752172772996435862085 3232653104105455965050963542144126174511394533404564441108024055494741938394025072191419617891117522318008347422011443414486128926583676768742567007693881344559331041118197192829056527517271092721789130219541733513936739042965284759338723988528222746197269437531287255281996931728692008497213985933191802690390832782941807565667827008827828868019579423203780580537598640335227507128786558318060894469586086822701421529196632338118637909214697798999651374849527946699078947574696434595717566197730108886278141589462144014534988130710310332989219299501490949224020558620508281843033139627563754250706198433133911650961955418863017030131341023979926769082692194917419036004919044502376249416391626435775606521801272070180851738672399053066070664843687291626156237856416982665263302877820820635441117202379057295745807639971171790511110931335841251926185678766926850270138494171674298460969125856781225969804 1755247756793686037125732490059066277910149489025762834423145527432874025739125761941884492016061674022498025924511047596727422239038863131551670688610872058060738734000130507330666577046705837339130587397738963347954858660279717092215258144293548814421824751222931009512925509851666913374542449219620575212195972582798148250455192265371033912726180462100509079204886961746688451125175946298567953600218569930391908288832637786607099475856298774219287831317970501988231013389902222737281322164185181956360231747553828359498403106268362761178716230325560725400079538201401283334159116328057723717712307983348645400306259579201934549460399437162109646898477258632812280913813011696409598483985085790316679828522616690442288464185933265109991939372296309035691635903011421813463672199183154795640198865944109898522581573392715087750824944127153132074420403208172603619731015375948038328909949014997 855621346364583049651755757607034401608668601171035526615008394183360755976485046768332488472377521462437364624135706102913777896567219718258475968028581700716259853832867443620941557577913585507181981361217796323205229031158670411041206954610619447718306264994164037535022654187355050703716437296185335231206453055446869816323210990145998431922720366570959844305532141814946224854843672630182857817452557220708598197801656646734241181374309484500522597228251315609896556566380393728225284222435505582578592393838413269337311559191470804917715216536067471935181230227349219608219734884284241922718295241751292323143328651782377247442476747500839364622386507047792218289360952428688327744070211928954466048783528260472603016655380845396132147940531970315730714754079360586586841816873554225103294532336956078035854777578637392107725698094217917066263206726726753744938807983333850597407 369941957363852037053003410279474816391823722932690003175756528860045519249130968063544770941634391185834542616036146391891044901572694190660680392733079223643729457064359195610897759651304773059153335869333214535732770720091854494611367353084848345054530099749073829447108865619686992745378043158361669578481905536152613241868659072845113634748784650047173389926736945234966353579225402522626336486310504123400013885107478372476734699239691660562215943834658902176561797467065736993357030303383988109473321081011325270133620538522029945607924384180926482975698638977662198216859849847588248148419376879584793000801386469829651374306597297108837725900777097461546848814007352002160044746856465558350965300431977568087647992315521995815262220437569368388155784246104231391449094792974954412991788482382355036302105284200682137186308411972361148628078939929605525616329130486764 139191364598100843671027168761130115333739203230073508584504049198713306948029606668367340592877421569262202328711352214631816344333430888224866663927910750217690398198507767286579692931128957428406466870713547237180753804673266321549300865385850018747167487230201326536136239330735653833069283919924711009354326646524735118602093950463534501810069560814698094813381528415549430024065315782636001023528948712921233203403275760464752945553398567810045911741183985712636733519308837258429584395999947098335342825835755617783240120577928324385395355601072972532493189303029050906187213598549002054867041009615131670995094676076847869555668748313657507176520813190907440336547182478133230201744715454258846238282811591909788614229538626699301214779199384582376920251846275459729250954320869202310577206597462674216996364687134766803137799019145507774282641931338193917126 44043562205733313414036828936504004429701054515845180285704927397182696140832887668786783975143554314666650588109907209444296723436732454131038103698094256184337863472429705445108750422844212892443517056326891764058203238993453983475342072912089462318310151640603493879178234343106906687646639974006265050741182575773918097627209932573998215394455430637451684558340227666732733171871174929978825049679206392052615486072747164309491396263119932669229470239722979076614818030839492587001718829636040617460890209483650534065684646884090968592356749997899187177334375897501229529442050888804562993595168864954254807250313656769086998073348710010793613307590002059463649318882670792705438035408867873165807303747666006673443131430948061577880104663642859799643744511302365497772748115064157215074175620549173005771474650437986127476366721735402899582825084713951 10861925002847327504320075403706795824019456223819973379272382447081129018235199666959659023101727367034539163597036405501200542617696994122772564647317696022147087009445291067309079115069929701338735350181801540429672590867240921627765049456452565474988868946933539776659454688256934520331273598832585642384750571654311572378032155149569838977608824214339423539102699201456694781585735937483863277218369590758105449347258392434502820444874497444771764310267081910137499708886201563652713494352196135379091471828692479382107370857606520827572904448137920679562258643533068128646856366248786885383763721493680392869952650819064642319983515151091744763609383560764830606666131134898471563533720399420844110910329565129960194288603446857171570761459348579411157619041698371464753094573881938944871956336061796983442128009603721161442952701445988490157 1594581635580909688870856131856948873962233789118578503093090414701998756676627323762619896703146499751113203432773544027609214366525969481917365329825852362231228051320747319565091520634757918269736022465030862748060849821127992742435418007246838382166242470327041621175989946906399383164995926127975797364033844659359519114943964391260672768238689425130122121072958719857430584745068854835057254870452296437218413852584338623949321798215333032181452173022958032143969953469954141519096247566523741119877846927660963667626122580477250091180649734659844292484949135918505832341910904689615744589748276674654430762667515177051483238717292311936381077164382595142828724182034867085752129370517700853572698774700025513525951609734112270450530335313883451375743271723233505227684663080786799962266443744364148697199454509544369192067795068620 -175258330374288488217699780681056007790738018516419452281991217832654531725817746986685120805050526934206221214211141521852994927206528251631399712058678982392880699800227124440195696214823380916708167445310792263345031242143035676279592625475734248832441286065902794254642514509741620998597884565902881353097461921842322070870984529159229514060165919622238464454116474141063130936752984696976799921351467288696273318318430019354280625161000802741257300306815204221600289221276550160895249928480353445064342116960056581099307365863716994163846551720672990602923358299428092665607545231959644829152413704506424911051622320036052874090548354320033672129426624281831899775321139548164347517142958538427511252378549150217840856725285327334555207840270205721245932505325761823123705947260438597139285994868809917490844945144025467690 -220204516996925692407481639318962275158355359698005005318968831105137877410318035105710030735253493203113614601148492718480669119594955222926330988813747084051194096829288602013708139413490389065268147594635456948867658605504940394238031555482960370191602547657627988580473271317223440356283286912868992645933201703098438403232137920212420959440102724896369844165067242271981986193800359091094747723345076794962221197090724157544666059314055602239994576519447991895833036047648279835490528709218893463307393510253353796421833052938499596293567284485949691751840926801159600011504013566712863640442505163583444721673287818969800667583958363492414161365095498214335337281791062974362643892979140568974220436080857130413612179269433508941820057605917648593877126906070657521089338116118571692083335137346253597230363346438 -86736665632678925155482178717541416902076376005607891408754495900348933434918513209452724010018685361893158041473663225587808925011797029588521260149269601655264376023270221929857106249729817265899694017319158207730930109639129622351016832288730019468523759267204415540775380151255429425512565935792592185965233296489721362856086319211357984593146960452637758443160166637910243405020664850087829521695097428554200043291734159717457440793421662838516158714294447522963772443831263641844249855189329155555845332410144343086066556665296069125595886804982098096438335788033789366633479851394765637333769728445267065432985566657279853389925618818844008343107578319219160786523354188227450128473210990504657882345063523456224912915046059727664646559655991260080589840205997564008010527878595560007930655715317990862 -21582126454742306667993456149556677980675932460298650535328848994746168325095862852666722458536329447597423387096751009305244842139050184544491450038967368144228011746022914115583645360623692331233474989474489219444393742965914046539434679463380651421037041943699498012845273895029251517240309503539746153134122836376598573102967018125553483751216696097816100791852880103103911552601264050283041915993619118558454428361434079044285011654871484945504053877664789720457201070079729484136519080360281111860909422248778061447745643765587425823404328107356657353938906970458620401013459131295171413389624086947025266759645994382891917066435893359532835153676706612710486528253286986244761712486266844971524920224154894618138915830104817136858848835666377534542360360110300083222617164486932381133489689581 -3197721395912341565564081952412110136169530860919163386385656007202973837007705327433023312125711351763473924016018786188937755919484674858599014596439712903164844770941217866141250736344714983164806546715253297791739899663831078378960721000334785698452304134226379392593908714462220788715616932619290014117079613611578414674308820766751225609804210768585733858466066057240133880231960864180798374206349802727313893774585143539099322978308588247355508151954504889114732631366814096556279917706062023211143064458274960070737668337702316425759599067738690845954429429400298407857211499431969609899228498434622943215486709416512227495363888797264000251869126601212793734657197459434337040578441217069635718989402007332910889176409302675400938019591258921490266883491293314586761456215738961770 -25183123559183134423074018635524921832567265127033408066598519830668308800738590152159316536479462511856139052375940167019153352366410191569916455774974730936481936472407740689794453537159299477945394874218179716458088007817339589177132979600490924502475782964795739644166657770467923215193227627376893261006656721851888476838139947219545442917759649093849334569809615727763573119590799216988467863818520639405700972431656022214085849172788952250025843472304147527886472940563732646744681254020329574575681719685485214262576685737122105672170725913417889623770432626301778650002211771426799598581241698478530425796305941118354222097953096626148205867114509728845372477611897334418262194839862537661129415586620561992889051163087412367496939111184741348290053889630495170354284007 128275949551782491640474118889911607242774013921143288004195427385429753191316410621073680915032415002991246233227241685218661767649500833260019371026766929922077186190252090680590646808375568580923518388358580405630116044119446285151876735370994962224616003501372549492788514039684921712846322649930896678422844654726772099788678741997475287649384944306743050933126902428578594909351375933898610844399632943765799134480756749732150738875295939401328991932923118218026009444193306285323722921890789771119859125621720604794898536055719867467868551264006568797001394242368280603685003713685417075488634011839908567853979278206769732648122467235571817039665159929122289138505819901539058492237967047125526640957265744234349635955895518407341265018302997163824746454137938087 36963842051408455627078292326095346501246419691467820566043752654928260360635708519143675203535094266715469760304060224887034201056737938410041473238542080972330131276773138012859711976027293161650646753000063680283470851169614128001621029560032089647000121540728734034873216463172295549679743717552505757877424913087495693058992361715922344628253564214783533834574720935823745285134657287539006424710364955973555231817000324626220956550772246888359548080627256851944674224116575128363053447942251208263767154007379582934196511400853751069963626767352734759344696048841379510765400102007519095595958932603531254720925841290118885854413489406727653366745404051980293900871756737680821341752735389489963057142251700893290170349570982879373958040232204173023894597 6067174578807453882753508695539020923333859968628303403913263562280670905602102213232710017631552907573770753069068140679475637462246560687301384947860220017158514402385174162671478980346080076597495562440866421626583532005762468447785804806628204738514111291246171469726298201141779388725308164318995081658226104112654075090713565816719599937473161020844843072726765709967526710443567524770323628072478886987184690619390671630875830952507603589427492242929410704976261817552061744654577645234599656211610253715579260456079722291995428674862563113864722845696773528951755788870714311116850396597345170291180807201764893656551450911123228743957132553672671394174588032604926396747714948205481344701433412957837221543194473981990173538847582486737301020 971164695550327316892471881277319230144861081825771285644418561121126514102955689748783732656538341192704824708237150063888076727774611503864966179200318939765919288445046521087555430815379597081937522609887476758129473089655827989487053701225651356542513908590686236171081594017781764761922710349346758377262798118275462154489349177944578221743389445540203506895642378539922840587871907292652558453453396357065517291921665634437090215929395048200343232386724384404583333781856076099664543319224848254642268353089301170089910494152967988433817567975947425876339410081317280834758550575869803559163798201156301489358203554822339031417391872906622726932181112253772995176180540797206282250073555909994274582396693822760802046170444942349140186 305036345493182155889442536292403071932596904420670668853502291563573867944598082511166761027895898173116934410911879913377548692099530873229032000817703467966997420724171955656509974496220898794905850355504313531829000951395618367904698857322853686129408450855805854071328499658844029561336767988651095243219847939247053250383854294500676536313935416993391926170132383451904184245262833764118599919155947685509575938361073495014692445254191349734304706389836339450591131002258675833002573374737502780762133276227409467670512009376094428722486750470394353067572548145747953124406467507224507612572529561059009136195017360664320871069052010795988350844840031450055643345848625572356540106608016932772566377206894261963399408707535429 105402147299284393801684646885778765742279178573992233031002910205250604702107223611864499918268527819101366742356007311005598768213571349766642491482728851958450950455889076721535783401002573368065986641078538028177544079941158139701344311765223277908415309351243081916785925470763744013483181045308661510512983799198957649602467883671699837397899465611265192162955058717050114297847549743385238281013700095022129633406711965279543685618083033571213158068909888120832409670101576348978811101537536208970395785467601852766952819049221485815628398517759178058517844029811060975065473131245800169534764075588719469992424624467622166627042982349012632687637915493827861315497693792261057017521680719980397862367373442917876157 25690485425700007333327111291046118052916546194109933954523067798738017855304967811892753709170039580388138276001812699286681159645069291618895891194879761696331727008600641934194473897886852528388560036713296401415074448604856009511906586657616465393600319522201499868805163005338376243350208867769783685669787198200747184429863674508841940316235553259068361994071128057351734893274960785298347081660660264238009720132244399784201277754062818527274311389411709867520460740661039284659109334041614417751085450050575155730149368510175650199046168852037071844173108903183316159364494461747307840277224000732804339394664231823372983684233671675576111529458692852486624912591483861819847132408468500128390390412482138 4215035667590888985965337359443737702195499617955407573077454563146784318779137203129821443296887722633551646953717495161745778610526621162333698225795054973314855581534019375834217718972908143471154846977571546017208423085406558162928278706853427103802761450898397243477928296062723848690389563178829255707841336335359415879160397344049578440289746047145057551995762998797567233587941639801361974253344177437179996074137443886617174425826822831268913377654925421417599260409139402113644684201977541552066007144688581988784173586755471581570836991346570105975945420711503849529541929295904156542683598760758845679378157072396937034110306179362927719659230904628961645530501360977522978808476694302943186 462608017710741149518921076515242367264310594099722535292736461315143127358867450486911423197949754642022766376343537286573284946456631788802043092001043896546292343099970117513140142876413958588930953599662628736745369506823323897452022806104104529802623340126278463345791040740606201163943262041386643332415085548334817258827802340131096308637534109003534454046336053946567998799673728380561979967733281395234989365130219066756264394109321296110934236015777796862896750313519753357650032471553283593689556428033365906555050953469040246556394965449213751121321069122824472412896675102149973952890085685970772980198278212100194335225120047097292109798954577716767576673399096865805426031898042 33862882529009830392485750866401109291648756085239885192082193097784920731593510260850294819451992370540561827534054561043033181886121065508178168097047466348896543655968913775469625023261852734567755690444784377082618901195121097163060014104094528589150920034706346712588776891700145293759544057581161523708488868539894989826251069867715958740770359882727101057333241529220124806976175891772510013657016401004102493186345636955722434001726286775167696494812419825444677061717883293199341538009742231099116825607061048095514686072084597278370412671931651845336784138496241689057151288722793849241157333200359325678533457807666714016815119119891017483729637924628747757394881277636790 1814623801974185696815411432306974014379062647175798499062528227782363002203191819942324519164433161232052472621761280070112514159919420240010712015103508983852372125429523943794433421628338145728876227573271925890034546001131071085439503633266645106075112295601727385107254180910165696906145047683869744641314125436224088096228900107268787766673078208658527478859567891322851448775940551764542001214799552683090377894121653548550575556075535747002343835038737644780867590842510832150540594815550414392332097232034612397903028036182050628308867653849432243505136662631356743179732676539609289709606155493542338238043241358032059032628463146842515700175757168778764095505759 93249888791181405042891390110774057102972740421065529154532451790004315096467048152350846217767211853115221918973072905637280639319499388476067438107304005045618477850818111196816958030142369907861726827052730264000569007382147991186409984517351604436769447197567185458368327875073308764506295090352637281036797615844448188127999213812845697180008086762047306094725568426355832344785271436502705237563126481219955894227622900528094243798610227925703776440230934671798963120546661856209134853604493722945315746084805142400631303978633284704971131134077611735198494799656712080010887074787301599408554520182158518438151437286098561879378410661311904076531922059185 4921498129852006424675299227573952821415882781331655892547799121843146815123947125603369893485756274753305528741917211894425572123308839699198568100362792179918425427995889493742458117705487858667254313174540216219309981972579082976319232928821327039892861057638179204340332660957287682233833005671999449095166127905075871387601986746761580173192664891901026731422751457459655514767954157000108433632026130871403579293221376313661255899621749906507629683182995716794782056017691100468715575369671957055745623421358122499170675579034750975916470271385931509184453519776648405650846194058985391901895227982621183162123025473842137674656349700426683056077 201272902562305689472571200491331851750049636933880578899333598076293964505742493042459180484126457126465401121797451596202908612946695380686396377033841585914389410302477301705112170287889865975851157757507465549323652763901840790205622628817939616400535635536652521657953857053611322588643586675183084699607388843166404226187657419153219853333625020688501210708293131524312769920565161689113511055648748532848818271016123653266692893441555288882689645026034714316432372128195031585720729197776036330109543487202131022997674917997849083896635639725036480827904589680949947237809251437137288956412469527468501734114310918240063291480050930942 6074751253304373699478103005423767194392460180178532242779132131883134798971251952194610961512672663543035654127756153712450507211561368973571976634207783355252804686544103676265001237260184773446824873437506138389881580498386927743109268036309633256751542644893511555286815487627956463069829692824237568007690960531273076445032010133947772936218555810889901230346272520955630280919825571309963348627906976862989869796455699119995006635298335538115452044779862172192986061031087449594487565989656917008256321642347817336596876445523851568976128441660664521879336687329733154120379435756686684095884126156330120727152201024121141435 158835640368624927032590567603298033578619460428181240275271178311247955906385358780880609108729731593000528649866256208791406940775600121819889914361157014596934714258355297904117710616353860489019083482117241921698807099414430612049481575726358558043601754835057019630102310430472592841252337908017889440767202384995675110755961647212986318461061788135296343800480157889647383498289820679293341354940262895884389598393484839276117181543909642716707954164229246657614251709668652420572710512949807247063044678349724511089981459422690779865347519696887457564045446080141772939950269568858082012591313957710183996464958422 3378902776872134909204839634350780570489386444602833200454760900258461158456475968767786638826676577991767426735542388159200737328011394812485955461262633296784485901814533654752799406903518798599048703026651458655257379291725908577613016050003151556791844209730414928304386452743655025491000998238763687307956696603617748086915536390338655047635126787848262872245644469285183252398652508297220725721995236789120114906732141512842760857593190120638372023923729622526452382862969080559959232688153460133906800190053367105284950075055827365166620172993694924414174980373672898385726820481538485431659006278194509 43079331259939515919275698578804185620986197244696798415016495720873670933657463215743464320826822818217043520103056534209916056157195395750471704735369170458016194728611156362683682500685550935485395203593729702769779759594200935064821306591638627011883484686976790112753212915600441815632077904449113748453399259468531763936142962291681638398372605510439393259145855884510266583260056334357613740785660705739276425104145786006056312697160438032838601633621767509204695962293044418377847996849526662006253108210889296421165933617690710605289828221283228905818261545639312850768818457519140627933059 241888549947281780453970332376533021011282816110362728271203139436475765057942802071196872840393868465027289459959410799788461175668613254139063157050636058392181269139232404141461880298738058796474652008228390097224085674472117318668135699123548934145057351803730650123864459215458336646869134720211474335685153578049826170902230696097090172541924249742742735455798580881018087903927097407092457336479159013029800043877603400653137762357381820397447743848915397214280255912384053813197361790665976579382707258006965027976397355870442671717523377265419561146645361069308842409716414749823 2376666192959846633516107374330794714748296292371435769889972320797571626802118600704583172570991283874821908434105402149381098559830077967475461633717911514260338342247661573203110589842201645894704836171721825311983421771649377974425053594782235622798898959134633315987735133144574981207375842994980940751142886625727144663673518413109414933454784015023169517143545340341136893308618175231432552370076990743951870797931924001487930023505152696548269229638467144136238737326349883098595437180422242838214426859842155775740707758296424184218989209744806567739431156071 12224062625832648183516693488530135118514258747173591610235394106191837482287498065840699381079070193230023620339082954952758518319905977223914718987561206209653761576001047130961967535872674537183498320220994771834545529715371523489357329178329639953948515526053154981117517445196850102059032579570738873131904056879673688661280476002767416938718011459524318277612243153293359296829432754457534753162164415110718998005028639349072782744247477763832792261907563795101315208763137730846936640573388864436242175078215481286793261658163010047075816510 1] ntl-11.5.1/src/QuadTestIn0000644417616742025610000000006614064716022016712 0ustar gid-shoupvpug-gid-shoupv1.333333333333333333333333 2.555555555555555555555555 ntl-11.5.1/src/QuadTestOut0000644417616742025610000000065314064716022017115 0ustar gid-shoupvpug-gid-shoupvPrecision OK 1.333333333333333333333333 2.555555555555555555555555 3.888888888888888888888888 3.888888888888888888888888 -1.222222222222222222222222 -1.222222222222222222222222 3.407407407407407407407406 3.407407407407407407407406 0.5217391304347826086956522 0.5217391304347826086956522 -1.333333333333333333333333 1.154700538379251529018297 0.1e21 long conversion OK long conversion OK ulong conversion OK ulong conversion OK ntl-11.5.1/src/GF2EXDivCross.cpp0000644417616742025610000000210714064716022017740 0ustar gid-shoupvpug-gid-shoupv#include #include namespace NTL { void DivRemPlain(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b, bool plain); } NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 2 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) long test(long k) { GF2X P; BuildIrred(P, k); GF2EPush push(P); for (long n = 25; ; n+=25) { cerr << ","; GF2EX a, b, q, r; random(a, 2*n); random(b, n); double t1, t2; TIME_IT(t1, DivRemPlain(q, r, a, b, false)); TIME_IT(t2, DivRemPlain(q, r, a, b, true)); double t = t1/t2; if (t <= 0.95) return n; } } int main() { cerr << "0.5 " << test(32) << "\n"; for (long i = 1; i <= 50; i++) { cerr << i << " " << test(64*i) << "\n"; } for (long i = 75; i <= 200 ; i+=25) { cerr << i << " " << test(64*i) << "\n"; } } ntl-11.5.1/src/GF2EXGCDCross.cpp0000644417616742025610000000273214064716022017617 0ustar gid-shoupvpug-gid-shoupv#include #include namespace NTL { void HalfGCD(GF2EX&,GF2EX&); void PlainRem(GF2EX& r, const GF2EX& a, const GF2EX& b, GF2XVec& x); } NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 2 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) void TestGCD1(long bnd, const GF2EX& a, const GF2EX& b) { long n = deg(a) + 1; GF2EX u(INIT_SIZE, n), v(INIT_SIZE, n); GF2XVec tmp(n, 2*GF2E::WordLength()); u = a; v = b; while (deg(v) > bnd) { PlainRem(u, u, v, tmp); swap(u, v); } } long test(long k) { GF2X P; BuildIrred(P, k); GF2EPush push(P); for (long n = 42; ; n = long(n*1.4)) { cerr << ","; GF2EX d, a, b, u, v; random(a, n); SetCoeff(a, n); random(b, n); double t1, t2; TIME_IT(t1, u=a; v=b; HalfGCD(u, v)); TIME_IT(t2, TestGCD1(deg(v), a, b)); double t = t1/t2; if (t <= 1) return n; } } int main() { #if 1 cerr << "0.5 " << test(32) << "\n"; for (long i = 1; i <= 4; i+=1) { cerr << i << " " << test(64*i) << "\n"; } for (long i = 8; i <= 16; i+=4) { cerr << i << " " << test(64*i) << "\n"; } #endif for (long i = 24; i <= 48; i+=8) { cerr << i << " " << test(64*i) << "\n"; } } ntl-11.5.1/src/GF2EXKarCross.cpp0000644417616742025610000000175314064716022017741 0ustar gid-shoupvpug-gid-shoupv#include #include namespace NTL { void PlainMul(GF2EX&,const GF2EX&,const GF2EX&); void mul_disable_plain(GF2EX&,const GF2EX&,const GF2EX&); } NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 2 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) long test(long k) { GF2X P; BuildIrred(P, k); GF2EPush push(P); for (long n = 2; ; n++) { cerr << ","; GF2EX a, b, c; random(a, n); random(b, n); double t1, t2; TIME_IT(t1, mul_disable_plain(c, a, b)); TIME_IT(t2, PlainMul(c, a, b)); double t = t1/t2; if (t <= 0.95) return n; } } int main() { cerr << "0.5 " << test(32) << "\n"; for (long i = 1; i <= 40; i++) { cerr << i << " " << test(64*i) << "\n"; } } ntl-11.5.1/src/GF2EXModCross.cpp0000644417616742025610000000204314064716022017734 0ustar gid-shoupvpug-gid-shoupv#include #include namespace NTL { void BuildPlain(GF2EXModulus& F, const GF2EX& f, bool plain); } NTL_CLIENT #define TIME_IT(t, action) \ do { \ double _t0, _t1; \ long _iter = 1; \ long _cnt = 0; \ do { \ _t0 = GetTime(); \ for (long _i = 0; _i < _iter; _i++) { action; _cnt++; } \ _t1 = GetTime(); \ } while ( _t1 - _t0 < 2 && (_iter *= 2)); \ t = (_t1 - _t0)/_iter; \ } while(0) long test(long k) { GF2X P; BuildIrred(P, k); GF2EPush push(P); for (long n = 5; ; n+=5) { cerr << ","; GF2EX a, r, f; random(a, 2*n-1); random(f, n); SetCoeff(f, n); GF2EXModulus F1, F2; BuildPlain(F1, f, false); BuildPlain(F2, f, true); double t1, t2; TIME_IT(t1, rem(r, a, F1)); TIME_IT(t2, rem(r, a, F2)); double t = t1/t2; if (t <= 0.95) return n; } } int main() { cerr << "0.5 " << test(32) << "\n"; for (long i = 1; i <= 40 ; i++) { cerr << i << " " << test(64*i) << "\n"; } } ntl-11.5.1/src/mach_desc.win0000644417616742025610000004214714064716022017401 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_mach_desc__H #define NTL_mach_desc__H #define NTL_BITS_PER_LONG (32) #define NTL_NUMBITS_BPL (6) #define NTL_MAX_LONG (2147483647L) #define NTL_MAX_INT (2147483647) #define NTL_BITS_PER_INT (32) #define NTL_BITS_PER_SIZE_T (32) #define NTL_ARITH_RIGHT_SHIFT (1) #define NTL_NBITS_MAX (30) #define NTL_WNBITS_MAX (30) #define NTL_DOUBLE_PRECISION (53) #define NTL_FDOUBLE_PRECISION (((double)(1L<<30))*((double)(1L<<22))) #define NTL_LONGDOUBLE_OK (0) #define NTL_WIDE_DOUBLE_DP ((wide_double(1L<<52))) #define NTL_QUAD_FLOAT_SPLIT ((((double)(1L<<27)))+1.0) #define NTL_EXT_DOUBLE (0) #define NTL_FMA_DETECTED (1) #define NTL_BIG_POINTERS (1) #define NTL_MIN_LONG (-NTL_MAX_LONG - 1L) #define NTL_MIN_INT (-NTL_MAX_INT - 1) #define NTL_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ lo = A[b & 7]; t = A[(b >> 3) & 7]; hi = t >> 29; lo ^= t << 3;\ t = A[(b >> 6) & 7]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 9) & 7]; hi ^= t >> 23; lo ^= t << 9;\ t = A[(b >> 12) & 7]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 15) & 7]; hi ^= t >> 17; lo ^= t << 15;\ t = A[(b >> 18) & 7]; hi ^= t >> 14; lo ^= t << 18;\ t = A[(b >> 21) & 7]; hi ^= t >> 11; lo ^= t << 21;\ t = A[(b >> 24) & 7]; hi ^= t >> 8; lo ^= t << 24;\ t = A[(b >> 27) & 7]; hi ^= t >> 5; lo ^= t << 27;\ t = A[b >> 30]; hi ^= t >> 2; lo ^= t << 30;\ if (a >> 31) hi ^= ((b & 0xb6db6db6UL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0x24924924UL) >> 2);\ c[0] = lo; c[1] = hi;\ #define NTL_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ if (a >> 31) hi ^= ((b & 0xeeeeeeeeUL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0xccccccccUL) >> 2);\ if ((a >> 29) & 1) hi ^= ((b & 0x88888888UL) >> 3);\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ if (a >> 31) hi ^= ((b & 0xeeeeeeeeUL) >> 1);\ if ((a >> 30) & 1) hi ^= ((b & 0xccccccccUL) >> 2);\ if ((a >> 29) & 1) hi ^= ((b & 0x88888888UL) >> 3);\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_HALF_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ lo = A[b & 3]; t = A[(b >> 2) & 3]; hi = t >> 30; lo ^= t << 2;\ t = A[(b >> 4) & 3]; hi ^= t >> 28; lo ^= t << 4;\ t = A[(b >> 6) & 3]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 8) & 3]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 10) & 3]; hi ^= t >> 22; lo ^= t << 10;\ t = A[(b >> 12) & 3]; hi ^= t >> 20; lo ^= t << 12;\ t = A[b >> 14]; hi ^= t >> 18; lo ^= t << 14;\ if (a >> 31) hi ^= ((b & 0xaaaaUL) >> 1);\ c[0] = lo; c[1] = hi;\ #define NTL_ALT_BB_MUL_CODE0 \ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ const _ntl_ulong t3 = A[(b >> 3) & 7]; \ const _ntl_ulong t6 = A[(b >> 6) & 7]; \ const _ntl_ulong t9 = A[(b >> 9) & 7]; \ const _ntl_ulong t12 = A[(b >> 12) & 7]; \ const _ntl_ulong t15 = A[(b >> 15) & 7]; \ const _ntl_ulong t18 = A[(b >> 18) & 7]; \ const _ntl_ulong t21 = A[(b >> 21) & 7]; \ const _ntl_ulong t24 = A[(b >> 24) & 7]; \ const _ntl_ulong t27 = A[(b >> 27) & 7]; \ const _ntl_ulong t30 = A[b >> 30]; \ const _ntl_ulong lo = A[b & 7] \ ^ (t3 << 3)\ ^ (t6 << 6)\ ^ (t9 << 9)\ ^ (t12 << 12)\ ^ (t15 << 15)\ ^ (t18 << 18)\ ^ (t21 << 21)\ ^ (t24 << 24)\ ^ (t27 << 27)\ ^ (t30 << 30);\ const _ntl_ulong hi = (t3 >> 29)\ ^ (t6 >> 26)\ ^ (t9 >> 23)\ ^ (t12 >> 20)\ ^ (t15 >> 17)\ ^ (t18 >> 14)\ ^ (t21 >> 11)\ ^ (t24 >> 8)\ ^ (t27 >> 5)\ ^ (t30 >> 2)\ ^ (((b & 0xb6db6db6UL) >> 1) & (-(a >> 31)))\ ^ (((b & 0x24924924UL) >> 2) & (-((a >> 30) & 1UL)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4)\ ^ (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4)\ ^ (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_ALT_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ const _ntl_ulong b = bp[i];\ const _ntl_ulong t4 = A[(b >> 4) & 15]; \ const _ntl_ulong t8 = A[(b >> 8) & 15]; \ const _ntl_ulong t12 = A[(b >> 12) & 15]; \ const _ntl_ulong t16 = A[(b >> 16) & 15]; \ const _ntl_ulong t20 = A[(b >> 20) & 15]; \ const _ntl_ulong t24 = A[(b >> 24) & 15]; \ const _ntl_ulong t28 = A[b >> 28]; \ const _ntl_ulong lo = A[b & 15] \ ^ (t4 << 4)\ ^ (t8 << 8)\ ^ (t12 << 12)\ ^ (t16 << 16)\ ^ (t20 << 20)\ ^ (t24 << 24)\ ^ (t28 << 28);\ const _ntl_ulong hi = (t4 >> 28)\ ^ (t8 >> 24)\ ^ (t12 >> 20)\ ^ (t16 >> 16)\ ^ (t20 >> 12)\ ^ (t24 >> 8)\ ^ (t28 >> 4);\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT_HALF_BB_MUL_CODE0 \ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ const _ntl_ulong t2 = A[(b >> 2) & 3]; \ const _ntl_ulong t4 = A[(b >> 4) & 3]; \ const _ntl_ulong t6 = A[(b >> 6) & 3]; \ const _ntl_ulong t8 = A[(b >> 8) & 3]; \ const _ntl_ulong t10 = A[(b >> 10) & 3]; \ const _ntl_ulong t12 = A[(b >> 12) & 3]; \ const _ntl_ulong t14 = A[b >> 14]; \ const _ntl_ulong lo = A[b & 3] \ ^ (t2 << 2)\ ^ (t4 << 4)\ ^ (t6 << 6)\ ^ (t8 << 8)\ ^ (t10 << 10)\ ^ (t12 << 12)\ ^ (t14 << 14);\ const _ntl_ulong hi = (t2 >> 30)\ ^ (t4 >> 28)\ ^ (t6 >> 26)\ ^ (t8 >> 24)\ ^ (t10 >> 22)\ ^ (t12 >> 20)\ ^ (t14 >> 18)\ ^ (((b & 0xaaaaUL) >> 1) & (-(a >> 31)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT1_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[8];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ lo = A[b & 7]; t = A[(b >> 3) & 7]; hi = t >> 29; lo ^= t << 3;\ t = A[(b >> 6) & 7]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 9) & 7]; hi ^= t >> 23; lo ^= t << 9;\ t = A[(b >> 12) & 7]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 15) & 7]; hi ^= t >> 17; lo ^= t << 15;\ t = A[(b >> 18) & 7]; hi ^= t >> 14; lo ^= t << 18;\ t = A[(b >> 21) & 7]; hi ^= t >> 11; lo ^= t << 21;\ t = A[(b >> 24) & 7]; hi ^= t >> 8; lo ^= t << 24;\ t = A[(b >> 27) & 7]; hi ^= t >> 5; lo ^= t << 27;\ t = A[b >> 30]; hi ^= t >> 2; lo ^= t << 30;\ hi ^= (((b & 0xb6db6db6UL) >> 1) & (-(a >> 31)))\ ^ (((b & 0x24924924UL) >> 2) & (-((a >> 30) & 1UL)));\ c[0] = lo; c[1] = hi;\ #define NTL_ALT1_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ hi ^= (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT1_BB_MUL_CODE2 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ hi ^= (((b & 0xeeeeeeeeUL) >> 1) & (-(a >> 31)))\ ^ (((b & 0xccccccccUL) >> 2) & (-((a >> 30) & 1UL)))\ ^ (((b & 0x88888888UL) >> 3) & (-((a >> 29) & 1UL)));\ cp[i] ^= (carry ^ lo); carry = hi;\ }\ cp[sb] ^= carry;\ #define NTL_ALT1_SHORT_BB_MUL_CODE1 \ long i;\ _ntl_ulong carry = 0, b;\ _ntl_ulong hi, lo, t;\ _ntl_ulong A[16];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ A[4] = A[2] << 1;\ A[5] = A[4] ^ A[1];\ A[6] = A[3] << 1;\ A[7] = A[6] ^ A[1];\ A[8] = A[4] << 1;\ A[9] = A[8] ^ A[1];\ A[10] = A[5] << 1;\ A[11] = A[10] ^ A[1];\ A[12] = A[6] << 1;\ A[13] = A[12] ^ A[1];\ A[14] = A[7] << 1;\ A[15] = A[14] ^ A[1];\ for (i = 0; i < sb; i++) {\ b = bp[i];\ lo = A[b & 15]; t = A[(b >> 4) & 15]; hi = t >> 28; lo ^= t << 4;\ t = A[(b >> 8) & 15]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 12) & 15]; hi ^= t >> 20; lo ^= t << 12;\ t = A[(b >> 16) & 15]; hi ^= t >> 16; lo ^= t << 16;\ t = A[(b >> 20) & 15]; hi ^= t >> 12; lo ^= t << 20;\ t = A[(b >> 24) & 15]; hi ^= t >> 8; lo ^= t << 24;\ t = A[b >> 28]; hi ^= t >> 4; lo ^= t << 28;\ cp[i] = carry ^ lo; carry = hi;\ }\ cp[sb] = carry;\ #define NTL_ALT1_HALF_BB_MUL_CODE0 \ _ntl_ulong hi, lo, t;\ _ntl_ulong A[4];\ A[0] = 0;\ A[1] = a;\ A[2] = A[1] << 1;\ A[3] = A[2] ^ A[1];\ lo = A[b & 3]; t = A[(b >> 2) & 3]; hi = t >> 30; lo ^= t << 2;\ t = A[(b >> 4) & 3]; hi ^= t >> 28; lo ^= t << 4;\ t = A[(b >> 6) & 3]; hi ^= t >> 26; lo ^= t << 6;\ t = A[(b >> 8) & 3]; hi ^= t >> 24; lo ^= t << 8;\ t = A[(b >> 10) & 3]; hi ^= t >> 22; lo ^= t << 10;\ t = A[(b >> 12) & 3]; hi ^= t >> 20; lo ^= t << 12;\ t = A[b >> 14]; hi ^= t >> 18; lo ^= t << 14;\ hi ^= (((b & 0xaaaaUL) >> 1) & (-(a >> 31)));\ c[0] = lo; c[1] = hi;\ #define NTL_BB_MUL1_BITS (4) #define NTL_BB_SQR_CODE \ lo=sqrtab[a&255];\ lo=lo|(sqrtab[(a>>8)&255]<<16);\ hi=sqrtab[(a>>16)&255];\ hi=hi|(sqrtab[(a>>24)&255]<<16);\ #define NTL_BB_REV_CODE (revtab[(a>>0)&255]<<24)\ |(revtab[(a>>8)&255]<<16)\ |(revtab[(a>>16)&255]<<8)\ |(revtab[(a>>24)&255]<<0) #endif ntl-11.5.1/src/Poly1TimeTest.cpp0000644417616742025610000001017314064716022020135 0ustar gid-shoupvpug-gid-shoupv #include #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #if defined(NTL_FFT_LAZYMUL) printf("FFT_LAZYMUL "); #endif #if defined(NTL_SPMM_ULL) printf("SPMM_ULL "); #endif #if defined(NTL_AVOID_BRANCHING) printf("AVOID_BRANCHING "); #endif #if defined(NTL_FFT_BIGTAB) printf("FFT_BIGTAB "); #endif printf("\n"); } int main() { SetSeed(ZZ(0)); long n, k; n = 200; k = 10*NTL_ZZ_NBITS; ZZ p; RandomLen(p, k); if (!IsOdd(p)) p++; ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " SetCoeff(f, n); // Sets coefficient of X^n to 1 // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { printf("999999999999999 "); print_flag(); return 0; } else if (r1 != r3) { printf("999999999999999 "); print_flag(); return 0; } double t; long i, j; long iter; const int nprimes = 30; const long L = 12; const long N = 1L << L; long r; for (r = 0; r < nprimes; r++) UseFFTPrime(r); vec_long A1[nprimes], A2[nprimes]; vec_long B1[nprimes], B2[nprimes]; for (r = 0; r < nprimes; r++) { A1[r].SetLength(N); A2[r].SetLength(N); B1[r].SetLength(N); B2[r].SetLength(N); for (i = 0; i < N; i++) { A1[r][i] = RandomBnd(GetFFTPrime(r)); A2[r][i] = RandomBnd(GetFFTPrime(r)); } } for (r = 0; r < nprimes; r++) { long *A1p = A1[r].elts(); long *A2p = A2[r].elts(); long *B1p = B1[r].elts(); long *B2p = B2[r].elts(); long q = GetFFTPrime(r); mulmod_t qinv = GetFFTPrimeInv(r); FFTFwd(B1p, A1p, L, r); FFTFwd(B2p, A2p, L, r); for (i = 0; i < N; i++) B1p[i] = NormalizedMulMod(B1p[i], B2p[i], q, qinv); FFTRev1(B1p, B1p, L, r); } iter = 1; do { t = GetTime(); for (j = 0; j < iter; j++) { for (r = 0; r < nprimes; r++) { long *A1p = A1[r].elts(); long *A2p = A2[r].elts(); long *B1p = B1[r].elts(); long *B2p = B2[r].elts(); long q = GetFFTPrime(r); mulmod_t qinv = GetFFTPrimeInv(r); FFTFwd(B1p, A1p, L, r); FFTFwd(B2p, A2p, L, r); for (i = 0; i < N; i++) B1p[i] = NormalizedMulMod(B1p[i], B2p[i], q, qinv); FFTRev1(B1p, B1p, L, r); } } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((3/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (j = 0; j < iter; j++) { for (r = 0; r < nprimes; r++) { long *A1p = A1[r].elts(); long *A2p = A2[r].elts(); long *B1p = B1[r].elts(); long *B2p = B2[r].elts(); long q = GetFFTPrime(r); mulmod_t qinv = GetFFTPrimeInv(r); FFTFwd(B1p, A1p, L, r); FFTFwd(B2p, A2p, L, r); for (i = 0; i < N; i++) B1p[i] = NormalizedMulMod(B1p[i], B2p[i], q, qinv); FFTRev1(B1p, B1p, L, r); } } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e13); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-11.5.1/src/Poly2TimeTest.cpp0000644417616742025610000000461614064716022020143 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #if (defined(NTL_TBL_REM)) printf("TBL_REM "); #else printf("DEFAULT "); #endif printf("\n"); } int main() { SetSeed(ZZ(0)); long n, k; n = 200; k = 10*NTL_ZZ_NBITS; ZZ p; RandomLen(p, k); if (!IsOdd(p)) p++; ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " SetCoeff(f, n); // Sets coefficient of X^n to 1 // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { printf("999999999999999 "); print_flag(); return 0; } else if (r1 != r3) { printf("999999999999999 "); print_flag(); return 0; } double t; long i; long iter; n = 1024; k = 1600; RandomLen(p, k); if (!IsOdd(p)) p++; ZZ_p::init(p); ZZ_pX a; random(a, n); long da = deg(a); ZZ_pXModRep modrep; ToZZ_pXModRep(modrep, a, 0, da); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { ToZZ_pXModRep(modrep, a, 0, da); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((3/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { ToZZ_pXModRep(modrep, a, 0, da); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e12); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-11.5.1/src/Poly3TimeTest.cpp0000644417616742025610000000510014064716022020131 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #if (defined(NTL_CRT_ALTCODE)) printf("CRT_ALTCODE "); #else printf("DEFAULT "); #endif printf("\n"); } int main() { SetSeed(ZZ(0)); long n, k; n = 1024; k = 30*NTL_SP_NBITS; ZZ p; RandomLen(p, k); if (!IsOdd(p)) p++; ZZ_p::init(p); // initialization ZZ_pX f, g, h, r1, r2, r3; random(g, n); // g = random polynomial of degree < n random(h, n); // h = " " random(f, n); // f = " " SetCoeff(f, n); // Sets coefficient of X^n to 1 // For doing arithmetic mod f quickly, one must pre-compute // some information. ZZ_pXModulus F; build(F, f); PlainMul(r1, g, h); // this uses classical arithmetic PlainRem(r1, r1, f); MulMod(r2, g, h, F); // this uses the FFT MulMod(r3, g, h, f); // uses FFT, but slower // compare the results... if (r1 != r2) { printf("999999999999999 "); print_flag(); return 0; } else if (r1 != r3) { printf("999999999999999 "); print_flag(); return 0; } double t; long i; long iter; ZZ_pX a, b, c; random(a, n); random(b, n); long da = deg(a); long db = deg(b); long dc = da + db; long l = NextPowerOfTwo(dc+1); FFTRep arep, brep, crep; ToFFTRep(arep, a, l, 0, da); ToFFTRep(brep, b, l, 0, db); mul(crep, arep, brep); ZZ_pXModRep modrep; FromFFTRep(modrep, crep); FromZZ_pXModRep(c, modrep, 0, dc); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { FromZZ_pXModRep(c, modrep, 0, dc); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((3/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { FromZZ_pXModRep(c, modrep, 0, dc); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e12); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-11.5.1/src/GF2XTimeTest.cpp0000644417616742025610000000430314064716022017635 0ustar gid-shoupvpug-gid-shoupv #include #include NTL_CLIENT double clean_data(double *t) { double x, y, z; long i, ix, iy, n; x = t[0]; ix = 0; y = t[0]; iy = 0; for (i = 1; i < 5; i++) { if (t[i] < x) { x = t[i]; ix = i; } if (t[i] > y) { y = t[i]; iy = i; } } z = 0; n = 0; for (i = 0; i < 5; i++) { if (i != ix && i != iy) z+= t[i], n++; } z = z/n; return z; } void print_flag() { #ifdef NTL_GF2X_ALTCODE printf("NTL_GF2X_ALTCODE "); #endif #ifdef NTL_GF2X_ALTCODE1 printf("NTL_GF2X_ALTCODE1 "); #endif #ifdef NTL_GF2X_NOINLINE printf("NTL_GF2X_NOINLINE "); #endif printf("\n"); } int main() { long n, i, j, iter, s, k; double t; SetSeed(ZZ(0)); for (i = 0; i < 10000; i++) { GF2X a, b, c, d; long da = RandomBnd(5*NTL_BITS_PER_LONG); long db = RandomBnd(5*NTL_BITS_PER_LONG); long dc = RandomBnd(5*NTL_BITS_PER_LONG); long dd = RandomBnd(5*NTL_BITS_PER_LONG); random(a, da); random(b, db); random(c, dc); random(d, dd); if ((a + b)*(c + d) != c*a + d*a + c*b + d*b) { printf("999999999999999 "); print_flag(); return 0; } } n = 16; s = 56; GF2X *a = new GF2X[s]; GF2X *b = new GF2X[s]; GF2X c; for (k = 0; k < s; k++) { random(a[k], (n + (k % 7))*NTL_BITS_PER_LONG); random(b[k], (n + (k % 8))*NTL_BITS_PER_LONG); } for (k = 0; k < s; k++) mul(c, a[k], b[k]); iter = 1; do { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 1; j++) for (k = 0; k < s; k++) mul(c, a[k], b[k]); } t = GetTime() - t; iter = 2*iter; } while(t < 1); iter = iter/2; iter = long((3/t)*iter) + 1; double tvec[5]; long w; for (w = 0; w < 5; w++) { t = GetTime(); for (i = 0; i < iter; i++) { for (j = 0; j < 1; j++) for (k = 0; k < s; k++) mul(c, a[k], b[k]); } t = GetTime() - t; tvec[w] = t; } t = clean_data(tvec); t = floor((t/iter)*1e14); if (t < 0 || t >= 1e15) printf("999999999999999 "); else printf("%015.0f ", t); printf(" [%ld] ", iter); print_flag(); return 0; } ntl-11.5.1/src/InitSettings.cpp0000644417616742025610000000733214064716022020101 0ustar gid-shoupvpug-gid-shoupv #include NTL_CLIENT #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int main() { #ifdef NTL_LEGACY_NO_NAMESPACE cout << "NTL_LEGACY_NO_NAMESPACE=1\n"; #else cout << "NTL_LEGACY_NO_NAMESPACE=0\n"; #endif #ifdef NTL_LEGACY_INPUT_ERROR cout << "NTL_LEGACY_INPUT_ERROR=1\n"; #else cout << "NTL_LEGACY_INPUT_ERROR=0\n"; #endif #ifdef NTL_THREADS cout << "NTL_THREADS=1\n"; #else cout << "NTL_THREADS=0\n"; #endif #ifdef NTL_TLS_HACK cout << "NTL_TLS_HACK=1\n"; #else cout << "NTL_TLS_HACK=0\n"; #endif #ifdef NTL_EXCEPTIONS cout << "NTL_EXCEPTIONS=1\n"; #else cout << "NTL_EXCEPTIONS=0\n"; #endif #ifdef NTL_THREAD_BOOST cout << "NTL_THREAD_BOOST=1\n"; #else cout << "NTL_THREAD_BOOST=0\n"; #endif #ifdef NTL_LEGACY_SP_MULMOD cout << "NTL_LEGACY_SP_MULMOD=1\n"; #else cout << "NTL_LEGACY_SP_MULMOD=0\n"; #endif #ifdef NTL_DISABLE_LONGDOUBLE cout << "NTL_DISABLE_LONGDOUBLE=1\n"; #else cout << "NTL_DISABLE_LONGDOUBLE=0\n"; #endif #ifdef NTL_DISABLE_LONGLONG cout << "NTL_DISABLE_LONGLONG=1\n"; #else cout << "NTL_DISABLE_LONGLONG=0\n"; #endif #ifdef NTL_DISABLE_LL_ASM cout << "NTL_DISABLE_LL_ASM=1\n"; #else cout << "NTL_DISABLE_LL_ASM=0\n"; #endif #ifdef NTL_MAXIMIZE_SP_NBITS cout << "NTL_MAXIMIZE_SP_NBITS=1\n"; #else cout << "NTL_MAXIMIZE_SP_NBITS=0\n"; #endif #ifdef NTL_GMP_LIP cout << "NTL_GMP_LIP=1\n"; #else cout << "NTL_GMP_LIP=0\n"; #endif #ifdef NTL_GF2X_LIB cout << "NTL_GF2X_LIB=1\n"; #else cout << "NTL_GF2X_LIB=0\n"; #endif #ifdef NTL_STD_CXX11 cout << "NTL_STD_CXX11=1\n"; #else cout << "NTL_STD_CXX11=0\n"; #endif #ifdef NTL_STD_CXX14 cout << "NTL_STD_CXX14=1\n"; #else cout << "NTL_STD_CXX14=0\n"; #endif #ifdef NTL_DISABLE_MOVE_ASSIGN cout << "NTL_DISABLE_MOVE_ASSIGN=1\n"; #else cout << "NTL_DISABLE_MOVE_ASSIGN=0\n"; #endif #ifdef NTL_DISABLE_MOVE cout << "NTL_DISABLE_MOVE=1\n"; #else cout << "NTL_DISABLE_MOVE=0\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cout << "FLAG_UNSIGNED_LONG_LONG_TYPE=1\n"; cout << "NTL_UNSIGNED_LONG_LONG_TYPE=" make_string(NTL_UNSIGNED_LONG_LONG_TYPE) "\n"; #else cout << "FLAG_UNSIGNED_LONG_LONG_TYPE=0\n"; cout << "NTL_UNSIGNED_LONG_LONG_TYPE=unsigned long long\n"; #endif #ifdef NTL_X86_FIX cout << "NTL_X86_FIX=1\n"; #else cout << "NTL_X86_FIX=0\n"; #endif #ifdef NTL_NO_X86_FIX cout << "NTL_NO_X86_FIX=1\n"; #else cout << "NTL_NO_X86_FIX=0\n"; #endif #ifdef NTL_NO_INIT_TRANS cout << "NTL_NO_INIT_TRANS=1\n"; #else cout << "NTL_NO_INIT_TRANS=0\n"; #endif #ifdef NTL_CLEAN_INT cout << "NTL_CLEAN_INT=1\n"; #else cout << "NTL_CLEAN_INT=0\n"; #endif #ifdef NTL_CLEAN_PTR cout << "NTL_CLEAN_PTR=1\n"; #else cout << "NTL_CLEAN_PTR=0\n"; #endif #ifdef NTL_SAFE_VECTORS cout << "NTL_SAFE_VECTORS=1\n"; #else cout << "NTL_SAFE_VECTORS=0\n"; #endif #ifdef NTL_ENABLE_AVX_FFT cout << "NTL_ENABLE_AVX_FFT=1\n"; #else cout << "NTL_ENABLE_AVX_FFT=0\n"; #endif #ifdef NTL_AVOID_AVX512 cout << "NTL_AVOID_AVX512=1\n"; #else cout << "NTL_AVOID_AVX512=0\n"; #endif #ifdef NTL_RANDOM_AES256CTR cout << "NTL_RANDOM_AES256CTR=1\n"; #else cout << "NTL_RANDOM_AES256CTR=0\n"; #endif #ifdef NTL_RANGE_CHECK cout << "NTL_RANGE_CHECK=1\n"; #else cout << "NTL_RANGE_CHECK=0\n"; #endif // the following are not actual config flags, but help // in the Wizard logic #ifdef NTL_LONGLONG_SP_MULMOD cout << "NTL_LONGLONG_SP_MULMOD=1\n"; #else cout << "NTL_LONGLONG_SP_MULMOD=0\n"; #endif #ifdef NTL_HAVE_PCLMUL cout << "NTL_HAVE_PCLMUL=1\n"; #else cout << "NTL_HAVE_PCLMUL=0\n"; #endif #ifdef NTL_HAVE_LL_TYPE cout << "NTL_HAVE_LL_TYPE=1\n"; #else cout << "NTL_HAVE_LL_TYPE=0\n"; #endif return 0; } ntl-11.5.1/src/DispSettings.cpp0000644417616742025610000000600714064716022020073 0ustar gid-shoupvpug-gid-shoupv #include #include using namespace std; #define make_string_aux(x) #x #define make_string(x) make_string_aux(x) int main() { cout << "\n\n"; cout << "/***************************\n"; cout << "Basic Configuration Options:\n"; #ifdef NTL_LEGACY_NO_NAMESPACE cout << "NTL_LEGACY_NO_NAMESPACE\n"; #endif #ifdef NTL_LEGACY_INPUT_ERROR cout << "NTL_LEGACY_INPUT_ERROR\n"; #endif #ifdef NTL_STD_CXX11 cout << "NTL_STD_CXX11\n"; #endif #ifdef NTL_STD_CXX14 cout << "NTL_STD_CXX14\n"; #endif #ifdef NTL_DISABLE_MOVE_ASSIGN cout << "NTL_DISABLE_MOVE_ASSIGN\n"; #endif #ifdef NTL_DISABLE_MOVE cout << "NTL_DISABLE_MOVE\n"; #endif #ifdef NTL_THREADS cout << "NTL_THREADS\n"; #endif #ifdef NTL_TLS_HACK cout << "NTL_TLS_HACK\n"; #endif #ifdef NTL_EXCEPTIONS cout << "NTL_EXCEPTIONS\n"; #endif #ifdef NTL_THREAD_BOOST cout << "NTL_THREAD_BOOST\n"; #endif #ifdef NTL_GMP_LIP cout << "NTL_GMP_LIP\n"; #endif #ifdef NTL_GF2X_LIB cout << "NTL_GF2X_LIB\n"; #endif #ifdef NTL_UNSIGNED_LONG_LONG_TYPE cout << "NTL_UNSIGNED_LONG_LONG_TYPE: "; cout << make_string(NTL_UNSIGNED_LONG_LONG_TYPE) << "\n"; #endif #ifdef NTL_X86_FIX cout << "NTL_X86_FIX\n"; #endif #ifdef NTL_NO_X86_FIX cout << "NTL_NO_X86_FIX\n"; #endif #ifdef NTL_NO_INIT_TRANS cout << "NTL_NO_INIT_TRANS\n"; #endif #ifdef NTL_CLEAN_INT cout << "NTL_CLEAN_INT\n"; #endif #ifdef NTL_CLEAN_PTR cout << "NTL_CLEAN_PTR\n"; #endif #ifdef NTL_SAFE_VECTORS cout << "NTL_SAFE_VECTORS\n"; #endif #ifdef NTL_ENABLE_AVX_FFT cout << "NTL_ENABLE_AVX_FFT\n"; #endif #ifdef NTL_AVOID_AVX512 cout << "NTL_AVOID_AVX512\n"; #endif #ifdef NTL_RANGE_CHECK cout << "NTL_RANGE_CHECK\n"; #endif #ifdef NTL_LEGACY_SP_MULMOD cout << "NTL_LEGACY_SP_MULMOD\n"; #endif #ifdef NTL_DISABLE_LONGDOUBLE cout << "NTL_DISABLE_LONGDOUBLE\n"; #endif #ifdef NTL_DISABLE_LONGLONG cout << "NTL_DISABLE_LONGLONG\n"; #endif #ifdef NTL_DISABLE_LL_ASM cout << "NTL_DISABLE_LL_ASM\n"; #endif #ifdef NTL_MAXIMIZE_SP_NBITS cout << "NTL_MAXIMIZE_SP_NBITS\n"; #endif cout << "\n"; cout << "Resolution of double-word type:\n"; cout << make_string(NTL_ULL_TYPE) << "\n"; cout << "\n"; cout << "Performance Options:\n"; #ifdef NTL_SPMM_ULL cout << "NTL_SPMM_ULL\n"; #endif #ifdef NTL_AVOID_BRANCHING cout << "NTL_AVOID_BRANCHING\n"; #endif #ifdef NTL_FFT_BIGTAB cout << "NTL_FFT_BIGTAB\n"; #endif #ifdef NTL_FFT_LAZYMUL cout << "NTL_FFT_LAZYMUL\n"; #endif #ifdef NTL_TBL_REM cout << "NTL_TBL_REM\n"; #endif #ifdef NTL_CRT_ALTCODE cout << "NTL_CRT_ALTCODE\n"; #endif #ifdef NTL_CRT_ALTCODE_SMALL cout << "NTL_CRT_ALTCODE_SMALL\n"; #endif #ifdef NTL_GF2X_ALTCODE cout << "NTL_GF2X_ALTCODE\n"; #endif #ifdef NTL_GF2X_ALTCODE1 cout << "NTL_GF2X_ALTCODE1\n"; #endif #ifdef NTL_GF2X_NOINLINE cout << "NTL_GF2X_NOINLINE\n"; #endif #ifdef NTL_RANDOM_AES256CTR cout << "NTL_RANDOM_AES256CTR\n"; #endif cout << "***************************/\n"; cout << "\n\n"; return 0; } ntl-11.5.1/src/WizardAux0000644417616742025610000001251414064716022016610 0ustar gid-shoupvpug-gid-shoupv# This is a perl script, invoked from a shell use warnings; # this doesn't work on older versions of perl sub GenConfigHeader { my $line; local *CFILE; local *CFILEOUT; open(CFILE, "< cfile"); open(CFILEOUT, "> cfileout"); while ($line = ) { $line =~ s/@\{(.*?)\}/$Config{$1}/ge; print CFILEOUT $line; } close(CFILE); close(CFILEOUT); system("cp cfileout ../include/NTL/config.h"); } sub RemoveProg { # This should work on unix and cygwin on windows my ($name) = @_; unlink($name); unlink("$name.exe"); } sub RunProg { my ($name) = @_; my $val; my $res; system("$ARGV[0] wclean") and return "999999999999999"; system("$ARGV[0] wntl.a") and return "999999999999999"; RemoveProg($name); system("$ARGV[0] $name") and return "999999999999999"; print "\n*** running $name..."; $val = `./$name`; if ($? != 0) { $res = "999999999999999"; } else { ($res) = ( $val =~ /^([0-9]*)/ ); } print $val, "\n"; return $res; } ############################################################ system("$ARGV[0] InitSettings"); @lines = `./InitSettings`; %Config = ( 'NTL_SPMM_ULL' => 0, 'NTL_TBL_REM' => 0, 'NTL_CRT_ALTCODE' => 0, 'NTL_CRT_ALTCODE_SMALL'=> 0, 'NTL_AVOID_BRANCHING' => 0, 'NTL_GF2X_ALTCODE' => 0, 'NTL_GF2X_ALTCODE1' => 0, 'NTL_GF2X_NOINLINE' => 0, 'NTL_FFT_BIGTAB' => 0, 'NTL_FFT_LAZYMUL' => 0, 'WIZARD_HACK' => '#define NTL_WIZARD_HACK', ); foreach $line (@lines) { chomp($line); ($name, $val) = ($line =~ /(.*?)=(.*)/); $Config{$name} = $val; } # set AVOID_BRANCHING, SPMM, and FFT flags...try all combinations $time = "999999999999999"; $aflag = "default"; $bflag = "default"; $cflag = "default"; $Config{"NTL_FFT_BIGTAB"} = 1; foreach $aflag1 ("default", "NTL_FFT_LAZYMUL") { foreach $bflag1 ("default", "NTL_SPMM_ULL") { foreach $cflag1 ("default", "NTL_AVOID_BRANCHING") { $Config{$aflag1} = 1; $Config{$bflag1} = 1; $Config{$cflag1} = 1; $skipit = 0; if ($Config{"NTL_SPMM_ULL"} == 1 && $Config{"NTL_HAVE_LL_TYPE"} == 0) { $skipit = 1; } if ($Config{"NTL_FFT_LAZYMUL"} == 1 && !($Config{"NTL_LONGLONG_SP_MULMOD"} == 1 || $Config{"NTL_SPMM_ULL"} == 1)) { $skipit = 1; } if ($Config{"NTL_LONGLONG_SP_MULMOD"} == 1 && $Config{"NTL_SPMM_ULL"} == 1) { $skipit = 1; } if ($skipit) { $Config{$aflag1} = 0; $Config{$bflag1} = 0; $Config{$cflag1} = 0; print "skip: $aflag1 $bflag1 $cflag1\n"; next; } print "run: $aflag1 $bflag1 $cflag1\n"; GenConfigHeader(); $time1 = RunProg("Poly1TimeTest"); if ($time1 < $time) { $aflag = $aflag1; $bflag = $bflag1; $cflag = $cflag1; $time = $time1; } $Config{$aflag1} = 0; $Config{$bflag1} = 0; $Config{$cflag1} = 0; } } } $Config{$aflag} = 1; $Config{$bflag} = 1; $Config{$cflag} = 1; # now see if BIGTAB really helps $Config{"NTL_FFT_BIGTAB"} = 0; print "run: $aflag $bflag $cflag default\n"; GenConfigHeader(); $time1 = RunProg("Poly1TimeTest"); if ($time1*1.0 > $time*1.04) { # stick with BIGTABs $Config{"NTL_FFT_BIGTAB"} = 1; } # set flags NTL_GF2X_NOINLINE, NTL_GF2X_ALTCODE, NTL_GF2X_ALTCODE1, # but not if we have PCLMUL if ($Config{'NTL_HAVE_PCLMUL'} == 0) { $time = "999999999999999"; $aflag = "default"; $bflag = "default"; foreach $aflag1 ("default", "NTL_GF2X_NOINLINE") { foreach $bflag1 ("default", "NTL_GF2X_ALTCODE", "NTL_GF2X_ALTCODE1") { $Config{$aflag1} = 1; $Config{$bflag1} = 1; GenConfigHeader(); $time1 = RunProg("GF2XTimeTest"); if ($time1 < $time) { $aflag = $aflag1; $bflag = $bflag1; $time = $time1; } $Config{$aflag1} = 0; $Config{$bflag1} = 0; } } $Config{$aflag} = 1; $Config{$bflag} = 1; } # set NTL_TBL_REM if ($Config{"NTL_HAVE_LL_TYPE"} == 1) { $time = "999999999999999"; $flag = "default"; foreach $flag1 ("default", "NTL_TBL_REM") { $Config{$flag1} = 1; GenConfigHeader(); $time1 = RunProg("Poly2TimeTest"); if ($time1 < $time) { $flag = $flag1; $time = $time1; } $Config{$flag1} = 0; } $Config{$flag} = 1; } # set NTL_CRT_ALTCODE if ($Config{"NTL_HAVE_LL_TYPE"} == 1 && $Config{"NTL_GMP_LIP"} == 1) { $time = "999999999999999"; $flag = "default"; foreach $flag1 ("default", "NTL_CRT_ALTCODE") { $Config{$flag1} = 1; GenConfigHeader(); $time1 = RunProg("Poly3TimeTest"); if ($time1 < $time) { $flag = $flag1; $time = $time1; } $Config{$flag1} = 0; } $Config{$flag} = 1; # set NTL_CRT_ALTCODE_SMALL, if NTL_CRT_ALTCODE # not set but it did not perform too badly if ($Config{"NTL_CRT_ALTCODE"} == 0) { # time measures default and time1 measures ALTCODE if (1.0*$time1 < 1.15*$time) { $Config{"NTL_CRT_ALTCODE_SMALL"} = 1; } } } $Config{'WIZARD_HACK'} = ""; GenConfigHeader(); print "\n\n*** the wizard is done!!\n\n"; system("$ARGV[0] DispSettings"); system("./DispSettings"); system("./DispSettings > wizard_log.h"); ntl-11.5.1/src/Wizard0000644417616742025610000000563014064716022016133 0ustar gid-shoupvpug-gid-shoupv if test "$1" = "on" then echo "" echo "*" echo "*" echo "* The wizard is going to run." echo "* It will perform some timing experiments, and then automatically" echo "* update your config.h file." echo "* Please be patient, and don't be spooked by any error messages." echo "*" echo "*" else echo "" echo "*" echo "*" echo "* You have chosen not to run the wizard." echo "*" echo "*" exit 0 fi rm -rf small mkdir small mkdir small/src mkdir small/include mkdir small/include/NTL cp Poly1TimeTest.cpp small/src cp Poly2TimeTest.cpp small/src cp Poly3TimeTest.cpp small/src cp GF2XTimeTest.cpp small/src cp InitSettings.cpp small/src cp DispSettings.cpp small/src cp FFT.cpp small/src cp GetTime.cpp small/src cp GetPID.cpp small/src cp ctools.cpp small/src cp ZZ.cpp small/src cp ZZVec.cpp small/src cp ZZ_p.cpp small/src cp ZZ_pX.cpp small/src cp ZZ_pX1.cpp small/src cp lip.cpp small/src cp tools.cpp small/src cp vec_ZZ.cpp small/src cp vec_ZZ_p.cpp small/src cp GF2.cpp small/src cp WordVector.cpp small/src cp vec_GF2.cpp small/src cp GF2X.cpp small/src cp GF2X1.cpp small/src cp thread.cpp small/src cp BasicThreadPool.cpp small/src cp fileio.cpp small/src sh CopyFeatures '..' small "$3" cp ../include/NTL/FFT.h small/include/NTL cp ../include/NTL/FFT_impl.h small/include/NTL cp ../include/NTL/ctools.h small/include/NTL cp ../include/NTL/ZZ.h small/include/NTL cp ../include/NTL/sp_arith.h small/include/NTL cp ../include/NTL/ZZVec.h small/include/NTL cp ../include/NTL/ZZ_p.h small/include/NTL cp ../include/NTL/ZZ_pX.h small/include/NTL cp ../include/NTL/config.h small/include/NTL cp ../include/NTL/lip.h small/include/NTL cp ../include/NTL/gmp_aux.h small/include/NTL cp ../include/NTL/mach_desc.h small/include/NTL cp ../include/NTL/new.h small/include/NTL cp ../include/NTL/SmartPtr.h small/include/NTL cp ../include/NTL/Lazy.h small/include/NTL cp ../include/NTL/LazyTable.h small/include/NTL cp ../include/NTL/thread.h small/include/NTL cp ../include/NTL/BasicThreadPool.h small/include/NTL cp ../include/NTL/fileio.h small/include/NTL cp ../include/NTL/tools.h small/include/NTL cp ../include/NTL/vec_ZZ.h small/include/NTL cp ../include/NTL/vec_ZZ_p.h small/include/NTL cp ../include/NTL/vec_long.h small/include/NTL cp ../include/NTL/vector.h small/include/NTL cp ../include/NTL/GF2.h small/include/NTL cp ../include/NTL/WordVector.h small/include/NTL cp ../include/NTL/vec_GF2.h small/include/NTL cp ../include/NTL/GF2X.h small/include/NTL cp ../include/NTL/PackageInfo.h small/include/NTL cp ../include/NTL/linux_s390x.h small/include/NTL cp cfile small/src cp WizardAux small/src cp makefile small/src cd small/src echo "*** perl WizardAux $2" perl WizardAux "$2" cd ../.. echo "*" echo "*" echo "* Updating config.h and wizard_log.h" echo "*" echo "*" cp small/include/NTL/config.h ../include/NTL/config.h cp small/src/wizard_log.h ../include/NTL/wizard_log.h rm -r small exit 0 ntl-11.5.1/src/DIRNAME0000644417616742025610000000001314064716022015740 0ustar gid-shoupvpug-gid-shoupvntl-11.5.1 ntl-11.5.1/src/WINDIR0000644417616742025610000000001614064716022015660 0ustar gid-shoupvpug-gid-shoupvWinNTL-11_5_1 ntl-11.5.1/src/VERSION_INFO0000644417616742025610000000000714064716022016624 0ustar gid-shoupvpug-gid-shoupv44:1:0 ntl-11.5.1/src/NOTES0000644417616742025610000000271614064716022015565 0ustar gid-shoupvpug-gid-shoupv ----------------------------- These are basically notes to myself on preparing a new distribution of NTL. ----------------------------- - make sure I update tour-time.html - update ../README and ../doc/copying.txt - change version numbers in ../include/NTL/version.h, DIRNAME, and WINDIR - change the libtool soname in VERSION_INFO. See: http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html - if changes were made to makefile or ../include/NTL/config.h, make sure these changes are implemented in the template files mfile and cfile, and then run: export COPYFILE_DISABLE=1 make ppdoc make ppclean make package make winpack ===================================== TODO: add a runtime flag that makes GetTime call GetWallTime FIXME: maybe it would make more sense to take the +1/-1 logic out of [cg]_lip_impl block_construct routines and just put it in the caller: the ZZ_p and ZZVec BlockConstruct stuff: add 1 there... that would mean in the ZZ_p ConstructFromVec we don't do the -1 either... not critical... FIXME: maybe add a reserve method to Vec, for compatibility with STL vectors. TODO list: * allow 32-bit SP MulMod...this would allow GPU/SSE support...both this and previous would require a complete scan to introduce new, special types * add template functions clear(), to clear multiple entries in a Vec or Poly. The important thing is to provide specialized ones for Vec and GF2X. ntl-11.5.1/src/CheckALIGNED_ARRAY.cpp0000644417616742025610000000041514064716023020410 0ustar gid-shoupvpug-gid-shoupv #define NTL_HAVE_ALIGNED_ARRAY // DIRT: we need to define this here so that ctools.h // tries the aligned array code...we only check // that it compiles without error #include #include using namespace std; int main() { return 0; } ntl-11.5.1/src/CheckBUILTIN_CLZL.cpp0000644417616742025610000000043714064716023020345 0ustar gid-shoupvpug-gid-shoupv#include #include using namespace std; long CountLeadingZeros(unsigned long x) { return __builtin_clzl(x); } int main() { unsigned long x = atoi("3"); if (CountLeadingZeros(x) == NTL_BITS_PER_LONG-2) return 0; else return -1; } ntl-11.5.1/src/CheckLL_TYPE.cpp0000644417616742025610000000130114064716023017552 0ustar gid-shoupvpug-gid-shoupv #define NTL_HAVE_LL_TYPE // DIRT: we need to define this here so that ctools.h // does not undefine the LL type macros #include #include #ifdef NTL_DISABLE_LONGLONG #error "LL_TYPE disabled" #endif using namespace std; int main() { if (sizeof(NTL_ULL_TYPE) != 2*sizeof(long)) return -1; unsigned long x1 = -atol("1"); unsigned long x2 = -atol("01"); unsigned long x3 = -atol("001"); unsigned long x4 = -atol("0001"); NTL_ULL_TYPE xx = ((NTL_ULL_TYPE) x1)*((NTL_ULL_TYPE) x2); NTL_ULL_TYPE yy = xx - ((((NTL_ULL_TYPE) x3) << (NTL_BITS_PER_LONG+1)) + 1); if (yy != 0) return -1; if (xx/x3 != x4) return -1; return 0; } ntl-11.5.1/src/CheckSSSE3.cpp0000644417616742025610000000200314064716023017242 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #include #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__SSSE3__)) #error "SSSE3 not supported" #endif #if (NTL_BITS_PER_LONG != 64 || NTL_BITS_PER_INT != 32 || NTL_DOUBLE_PRECISION != 53) #error "SSSE3 not supported" // sanity check -- code that uses this feature also relies on this #endif #ifndef NTL_HAVE_ALIGNED_ARRAY #error "SSSE3 not supported" #endif #define ROL_VEC_8(x) _mm_shuffle_epi8(x,_mm_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3)) using namespace std; void fun(unsigned int* x, const unsigned int *a) { __m128i xvec, avec; avec = _mm_loadu_si128((const __m128i *) a); xvec = ROL_VEC_8(avec); _mm_storeu_si128((__m128i *)x, xvec); } int main() { unsigned int a[4]; unsigned int x[4]; for (long i = 0; i < 4; i++) { a[i] = atoi("0") + i; } fun(x, a); for (long i = 0; i < 4; i++) { if (x[i] != 256*i) return -1; } return 0; } ntl-11.5.1/src/CheckAVX.cpp0000644417616742025610000000234314064716023017047 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__AVX__)) #error "AVX not supported" #endif #if (NTL_BITS_PER_LONG != 64 || NTL_BITS_PER_INT != 32 || NTL_DOUBLE_PRECISION != 53) #error "AVX not supported" // sanity check -- code that uses this feature also relies on this #endif #ifndef NTL_HAVE_ALIGNED_ARRAY #error "AVX not supported" #endif using namespace std; void fun(double * x, const double *a, const double *b) { __m256d xvec, avec, bvec, cvec; avec = _mm256_load_pd(a); bvec = _mm256_load_pd(b); xvec = _mm256_load_pd(x); xvec = _mm256_add_pd(_mm256_mul_pd(avec, bvec), xvec); _mm256_store_pd(x, xvec); } int main() { NTL_AVX_LOCAL_ARRAY(vp, double, 12); double *a = vp + 0*4; double *b = vp + 1*4; double *x = vp + 2*4; a[0] = atoi("1"); a[1] = atoi("2"); a[2] = atoi("3"); a[3] = atoi("4"); b[0] = atoi("2"); b[1] = atoi("3"); b[2] = atoi("4"); b[3] = atoi("5"); x[0] = atoi("3"); x[1] = atoi("4"); x[2] = atoi("5"); x[3] = atoi("6"); fun(x, a, b); if (x[0] == 5 && x[1] == 10 && x[2] == 17 && x[3] == 26) return 0; else return -1; } ntl-11.5.1/src/CheckPCLMUL.cpp0000644417616742025610000000176014064716023017407 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__AVX__)) #error "PCLMUL not supported" #endif #if (NTL_BITS_PER_LONG != 64) #error "PCLMUL not supported" #endif // NOTE: gcc and clang define __PCLMUL__, but icc does not using namespace std; static inline void pclmul_mul1 (unsigned long *c, unsigned long a, unsigned long b) { __m128i aa = _mm_setr_epi64( _mm_cvtsi64_m64(a), _mm_cvtsi64_m64(0)); __m128i bb = _mm_setr_epi64( _mm_cvtsi64_m64(b), _mm_cvtsi64_m64(0)); _mm_storeu_si128((__m128i*)c, _mm_clmulepi64_si128(aa, bb, 0)); } int main() { unsigned long a = ((unsigned long) atoi("15")) << (NTL_BITS_PER_LONG-4); unsigned long b = atoi("4"); unsigned long c[2]; pclmul_mul1(c, a, b); unsigned long c0 = ((unsigned long) atoi("3")) << (NTL_BITS_PER_LONG-2); unsigned long c1 = atoi("3"); if (c[0] == c0 && c[1] == c1) return 0; else return -1; } ntl-11.5.1/src/CheckAVX2.cpp0000644417616742025610000000163314064716023017132 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__AVX2__)) #error "AVX2 not supported" #endif #if (NTL_BITS_PER_LONG != 64 || NTL_BITS_PER_INT != 32 || NTL_DOUBLE_PRECISION != 53) #error "AVX2 not supported" // sanity check -- code that uses this feature also relies on this #endif #ifndef NTL_HAVE_ALIGNED_ARRAY #error "AVX2 not supported" #endif using namespace std; void fun(unsigned int* x, const unsigned int *a) { __m256i xvec, avec; avec = _mm256_loadu_si256((const __m256i *) a); xvec = _mm256_slli_epi32(avec, 5); _mm256_storeu_si256((__m256i *)x, xvec); } int main() { unsigned int a[8]; unsigned int x[8]; for (long i = 0; i < 7; i++) { a[i] = atoi("0") + i; } fun(x, a); for (long i = 0; i < 7; i++) { if (x[i] != 32*i) return -1; } return 0; } ntl-11.5.1/src/CheckFMA.cpp0000644417616742025610000000236614064716023017021 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__AVX2__)) #error "AVX2 with FMA not supported" #endif #if (NTL_BITS_PER_LONG != 64 || NTL_BITS_PER_INT != 32 || NTL_DOUBLE_PRECISION != 53) #error "AVX2 with FMA not supported" // sanity check -- code that uses this feature also relies on this #endif #ifndef NTL_HAVE_ALIGNED_ARRAY #error "AVX2 with FMA not supported" #endif using namespace std; void fun(double * x, const double *a, const double *b) { __m256d xvec, avec, bvec, cvec; avec = _mm256_load_pd(a); bvec = _mm256_load_pd(b); xvec = _mm256_load_pd(x); xvec = _mm256_fmadd_pd(avec, bvec, xvec); _mm256_store_pd(x, xvec); } int main() { NTL_AVX_LOCAL_ARRAY(vp, double, 12); double *a = vp + 0*4; double *b = vp + 1*4; double *x = vp + 2*4; a[0] = atoi("1"); a[1] = atoi("2"); a[2] = atoi("3"); a[3] = atoi("4"); b[0] = atoi("2"); b[1] = atoi("3"); b[2] = atoi("4"); b[3] = atoi("5"); x[0] = atoi("3"); x[1] = atoi("4"); x[2] = atoi("5"); x[3] = atoi("6"); fun(x, a, b); if (x[0] == 5 && x[1] == 10 && x[2] == 17 && x[3] == 26) return 0; else return -1; } ntl-11.5.1/src/CheckAVX512F.cpp0000644417616742025610000000406714064716023017412 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include // Ths actually checks for AVX512F+DQ+VL #if (!defined(__GNUC__) || !defined(__x86_64__) || !defined(__AVX512F__)) #error "AVX512F not supported" #endif #if (!defined(__AVX512VL__) || !defined(__AVX512DQ__)) #error "AVX512F not supported" #endif #if (NTL_BITS_PER_LONG != 64 || NTL_BITS_PER_INT != 32 || NTL_DOUBLE_PRECISION != 53) #error "AVX512F not supported" // sanity check -- code that uses this feature also relies on this #endif #ifndef NTL_HAVE_ALIGNED_ARRAY #error "AVX512F not supported" #endif using namespace std; void fun(double * x, const double *a, const double *b) { __m512d xvec, avec, bvec, cvec; avec = _mm512_load_pd(a); bvec = _mm512_load_pd(b); xvec = _mm512_load_pd(x); xvec = _mm512_fmadd_pd(avec, bvec, xvec); _mm512_store_pd(x, xvec); } void fun1(double *x, const long *p) { __m256i a = _mm256_load_si256((const __m256i*)p); _mm256_store_pd(x, _mm256_cvtepi64_pd(a)); } int main() { NTL_AVX512_LOCAL_ARRAY(vp, double, 24); double *a = vp + 0*8; double *b = vp + 1*8; double *x = vp + 2*8; a[0] = atoi("1"); a[1] = atoi("2"); a[2] = atoi("3"); a[3] = atoi("4"); a[4] = atoi("5"); a[5] = atoi("6"); a[6] = atoi("7"); a[7] = atoi("8"); b[0] = atoi("2"); b[1] = atoi("3"); b[2] = atoi("4"); b[3] = atoi("5"); b[4] = atoi("6"); b[5] = atoi("7"); b[6] = atoi("8"); b[7] = atoi("9"); x[0] = atoi("3"); x[1] = atoi("4"); x[2] = atoi("5"); x[3] = atoi("6"); x[4] = atoi("7"); x[5] = atoi("8"); x[6] = atoi("9"); x[7] = atoi("10"); fun(x, a, b); NTL_AVX_LOCAL_ARRAY(lp, long, 4); NTL_AVX_LOCAL_ARRAY(dp, double, 4); lp[0] = atoi("1"); lp[1] = atoi("2"); lp[2] = atoi("3"); lp[3] = atoi("4"); fun1(dp, lp); if (x[0] == 5 && x[1] == 10 && x[2] == 17 && x[3] == 26 && x[4] == 37 && x[5] == 50 && x[6] == 65 && x[7] == 82 && dp[0] == 1 && dp[1] == 2 && dp[2] == 3 && dp[3] == 4) return 0; else return -1; } ntl-11.5.1/src/CheckCOPY_TRAITS1.cpp0000644417616742025610000000244314064716023020333 0ustar gid-shoupvpug-gid-shoupv#include template constexpr bool Relocate_aux_has_trivial_copy(T*) { return std::is_trivially_copyable::value && std::is_trivially_destructible::value && std::is_copy_constructible::value; } struct A { A(const A&) = delete; }; struct B { ~B() {} }; struct C { virtual void foo() { } }; struct D { private: D(const D&); }; struct E { private: E(const E&) = default; }; struct AA { A a; }; struct BB { B b; }; struct CC { C c; }; struct DD { D d; }; struct EE { E e; }; struct X { int x; }; struct XX { private: X x; }; int main() { if ( !Relocate_aux_has_trivial_copy((A*)0) && !Relocate_aux_has_trivial_copy((B*)0) && !Relocate_aux_has_trivial_copy((C*)0) && !Relocate_aux_has_trivial_copy((D*)0) && !Relocate_aux_has_trivial_copy((E*)0) && !Relocate_aux_has_trivial_copy((AA*)0) && !Relocate_aux_has_trivial_copy((BB*)0) && !Relocate_aux_has_trivial_copy((CC*)0) && !Relocate_aux_has_trivial_copy((DD*)0) && !Relocate_aux_has_trivial_copy((EE*)0) && Relocate_aux_has_trivial_copy((X*)0) && Relocate_aux_has_trivial_copy((XX*)0) && Relocate_aux_has_trivial_copy((int*)0) ) return 0; else return -1; } ntl-11.5.1/src/CheckCOPY_TRAITS2.cpp0000644417616742025610000000377014064716023020340 0ustar gid-shoupvpug-gid-shoupv#include template struct Relocate_aux_Failable { typedef out type; }; template struct Relocate_aux_has_copy { static const T *MakeT(); template // U and T are the same type static typename Relocate_aux_Failable<(unsigned(sizeof U(*MakeT()))), std::true_type>::type copy(int); template static typename Relocate_aux_Failable<0U, std::false_type>::type copy(...); constexpr static bool value = decltype( copy(0) )::value; }; template constexpr bool Relocate_aux_has_trivial_copy(T*) { return __has_trivial_copy(T) && __has_trivial_destructor(T) && Relocate_aux_has_copy::value; } struct A { A(const A&) = delete; }; struct B { ~B() {} }; struct C { virtual void foo() { } }; struct D { private: D(const D&); }; struct E { private: E(const E&) = default; }; struct AA { A a; }; struct BB { B b; }; struct CC { C c; }; struct DD { D d; }; struct EE { E e; }; struct X { int x; }; struct XX { private: X x; }; int main() { if ( !Relocate_aux_has_trivial_copy((A*)0) && !Relocate_aux_has_trivial_copy((B*)0) && !Relocate_aux_has_trivial_copy((C*)0) && !Relocate_aux_has_trivial_copy((D*)0) && !Relocate_aux_has_trivial_copy((E*)0) && !Relocate_aux_has_trivial_copy((AA*)0) && !Relocate_aux_has_trivial_copy((BB*)0) && !Relocate_aux_has_trivial_copy((CC*)0) && !Relocate_aux_has_trivial_copy((DD*)0) && #ifndef __INTEL_COMPILER !Relocate_aux_has_trivial_copy((EE*)0) && // Ignore a bug in the Intel compiler. It really does // allow the use of this copy constructor (which should have been // deleted), so the problem is not in the *detection* of this // property. #endif Relocate_aux_has_trivial_copy((X*)0) && Relocate_aux_has_trivial_copy((XX*)0) && Relocate_aux_has_trivial_copy((int*)0) ) return 0; else return -1; } ntl-11.5.1/src/CheckCHRONO_TIME.cpp0000644417616742025610000000056214064716023020220 0ustar gid-shoupvpug-gid-shoupv#include #if (NTL_CXX_STANDARD >= 2011) #include double _ntl_GetWallTime( ) { auto current_time = std::chrono::steady_clock::now(); auto duration_in_seconds = std::chrono::duration(current_time.time_since_epoch()); return duration_in_seconds.count(); } #endif int main() { double t = _ntl_GetWallTime( ); return 0; } ntl-11.5.1/src/CheckMACOS_TIME.cpp0000644417616742025610000000114714064716023020072 0ustar gid-shoupvpug-gid-shoupv #if defined(__MACH__) && defined(__APPLE__) #include #include static inline double InitTimeConvert() { mach_timebase_info_data_t timeBase; (void)mach_timebase_info( &timeBase ); return (double)timeBase.numer / (double)timeBase.denom / 1000000000.0; } double _ntl_GetWallTime( ) { static double timeConvert = InitTimeConvert(); // even in a multi-threaded environment, this will // be safely initialized, according to C++11 standard return double(mach_absolute_time()) * timeConvert; } #endif int main() { double t = _ntl_GetWallTime( ); return 0; } ntl-11.5.1/src/CheckPOSIX_TIME.cpp0000644417616742025610000000122214064716023020124 0ustar gid-shoupvpug-gid-shoupv #include #if defined(_POSIX_VERSION) && defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) #include #if defined(CLOCK_MONOTONIC) #define Clk_ID CLOCK_MONOTONIC #elif defined(CLOCK_REALTIME) #define Clk_ID CLOCK_REALTIME #elif defined(CLOCK_HIGHRES) #define Clk_ID CLOCK_HIGHRES #endif #endif #if (defined(Clk_ID)) // POSIX clock_gettime() int retval; double _ntl_GetWallTime( ) { using namespace std; timespec ts; if ((retval=clock_gettime(Clk_ID, &ts))) return -1; else return double(ts.tv_sec) + double(ts.tv_nsec) / 1000000000.0; } #endif int main() { double t = _ntl_GetWallTime(); return retval; } ntl-11.5.1/src/CheckAES_NI.cpp0000644417616742025610000000072314064716023017407 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include #include #include using namespace std; #if (NTL_BITS_PER_LONG != 64) #error "NTL_BITS_PER_LONG != 64" #endif int main() { __m128i a=_mm_cvtsi64x_si128(atol("17")); __m128i key=_mm_cvtsi64x_si128(atol("42")); a = _mm_aesenclast_si128(a, key); long x = _mm_cvtsi128_si64x(a); if (x != atol("7161677110969590696")) return -1; return 0; } ntl-11.5.1/src/CheckKMA.cpp0000644417616742025610000000157314064716023017025 0ustar gid-shoupvpug-gid-shoupv#include #include #include #include using namespace std; #if !defined(LINUX_S390X) #error "KMA not supported" #endif int main() { #if defined(AT_HWCAP) && defined(HWCAP_S390_STFLE) unsigned long hwcap, facility_list_nmemb; uint64_t status_word[2], facility_list[3]; /* Check for STFLE. */ hwcap = getauxval(AT_HWCAP); if (!(hwcap & HWCAP_S390_STFLE)) return -1; /* Query facility list. */ facility_list_nmemb = stfle(facility_list, 3); /* Check MSA8. */ if (facility_list_nmemb >= OFF64(MSA8) + 1 && (facility_list[OFF64(MSA8)] & MASK64(MSA8))) { cpacf_kma(CPACF_KMA_QUERY, &status_word, NULL, NULL, 0, NULL, 0); if (status_word[OFF64(CPACF_KMA_GCM_AES_256)] & MASK64(CPACF_KMA_GCM_AES_256)) { return 0; } } #endif return -1; } ntl-11.5.1/src/libtool-seed/0000755417616742025610000000000014064716023017327 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/libtool-seed/Makefile.am0000644417616742025610000000000014064716023021351 0ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/libtool-seed/configure.ac0000644417616742025610000000021314064716023021611 0ustar gid-shoupvpug-gid-shoupvAC_INIT(ntl-libtool, 1.0) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_FILES([Makefile]) LT_INIT AC_PROG_CXX AC_PROG_CC AC_PROG_LIBTOOL AC_OUTPUT ntl-11.5.1/src/libtool-origin/0000755417616742025610000000000014064716023017676 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/libtool-origin/Makefile.am0000644417616742025610000000000014064716023021720 0ustar gid-shoupvpug-gid-shoupvntl-11.5.1/src/libtool-origin/Makefile.in0000644417616742025610000004153614064716023021754 0ustar gid-shoupvpug-gid-shoupv# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) config.guess \ config.sub install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ all: all-am .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am am--refresh check check-am clean clean-generic \ clean-libtool cscopelist-am ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-libtool \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ntl-11.5.1/src/libtool-origin/aclocal.m40000644417616742025610000124474114064716023021553 0ustar gid-shoupvpug-gid-shoupv# generated automatically by aclocal 1.13.4 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.4], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.4])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR ntl-11.5.1/src/libtool-origin/config.guess0000755417616742025610000013036114064716023022222 0ustar gid-shoupvpug-gid-shoupv#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ntl-11.5.1/src/libtool-origin/config.sub0000755417616742025610000010531514064716023021666 0ustar gid-shoupvpug-gid-shoupv#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-04-24' # This file 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ntl-11.5.1/src/libtool-origin/configure0000755417616742025610000210247214064716023021615 0ustar gid-shoupvpug-gid-shoupv#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for ntl-libtool 1.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ntl-libtool' PACKAGE_TARNAME='ntl-libtool' PACKAGE_VERSION='1.0' PACKAGE_STRING='ntl-libtool 1.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_shared enable_static with_pic enable_fast_install enable_dependency_tracking with_gnu_ld with_sysroot enable_libtool_lock ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC CXXCPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures ntl-libtool 1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/ntl-libtool] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of ntl-libtool 1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-libtool-lock avoid locking (might break parallel builds) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF ntl-libtool configure 1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by ntl-libtool $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.13' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='ntl-libtool' VERSION='1.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' ac_config_files="$ac_config_files Makefile" case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu else _lt_caught_CXX_error=yes fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds reload_flag_CXX=$reload_flag reload_cmds_CXX=$reload_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec_CXX='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty # executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath__CXX+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath__CXX fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' fi archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared # libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_CXX=' ' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=yes file_list_spec_CXX='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' enable_shared_with_static_runtimes_CXX=yes # Don't use ranlib old_postinstall_cmds_CXX='chmod 644 $oldlib' postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec_CXX='' fi link_all_deplibs_CXX=yes allow_undefined_flag_CXX="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" if test "$lt_cv_apple_cc_single_mod" != "yes"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; haiku*) archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs_CXX=yes ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5].* | *pgcpp\ [1-5].*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ '"$old_archive_cmds_CXX" reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ '"$reload_cmds_CXX" ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) # IBM XL 8.0, 9.0 on PPC and BlueGene lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' ;; esac ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc_CXX=no else lt_cv_archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 $as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink || test "$inherit_rpath_CXX" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by ntl-libtool $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ ntl-libtool config.status 1.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ reload_flag_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_separator_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ reload_cmds_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX \ postlink_cmds_CXX; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # How to create reloadable object files. reload_flag=$lt_reload_flag_CXX reload_cmds=$lt_reload_cmds_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ntl-11.5.1/src/libtool-origin/configure.ac0000644417616742025610000000021314064716023022160 0ustar gid-shoupvpug-gid-shoupvAC_INIT(ntl-libtool, 1.0) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_FILES([Makefile]) LT_INIT AC_PROG_CXX AC_PROG_CC AC_PROG_LIBTOOL AC_OUTPUT ntl-11.5.1/src/libtool-origin/install-sh0000755417616742025610000003325514064716023021712 0ustar gid-shoupvpug-gid-shoupv#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated 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 # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ntl-11.5.1/src/libtool-origin/ltmain.sh0000644417616742025610000105152214064716023021524 0ustar gid-shoupvpug-gid-shoupv # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION=2.4.2 TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 ntl-11.5.1/src/libtool-origin/missing0000755417616742025610000001533114064716023021300 0ustar gid-shoupvpug-gid-shoupv#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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, 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ntl-11.5.1/include/0000755417616742025610000000000014064716022015600 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/include/NTL/0000755417616742025610000000000014064716023016236 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/include/NTL/FFT.h0000644417616742025610000001365214064716022017034 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_FFT__H #define NTL_FFT__H #include #include #include #include #include NTL_OPEN_NNS #define NTL_PROVIDES_TRUNC_FFT #define NTL_FFTFudge (4) // This constant is used in selecting the correct // number of FFT primes for polynomial multiplication // in ZZ_pX and zz_pX. Set at 4, this allows for // two FFT reps to be added or subtracted once, // before performing CRT, and leaves a reasonable margin for error. // Don't change this! #define NTL_FFTMaxRootBnd (NTL_SP_NBITS-2) // Absolute maximum root bound for FFT primes. // Don't change this! #if (25 <= NTL_FFTMaxRootBnd) #define NTL_FFTMaxRoot (25) #else #define NTL_FFTMaxRoot NTL_FFTMaxRootBnd #endif // Root bound for FFT primes. Held to a maximum // of 25 to avoid large tables and excess precomputation, // and to keep the number of FFT primes needed small. // This means we can multiply polynomials of degree less than 2^24. // This can be increased, with a slight performance penalty. // PIPL pattern: FFTMulTabs defined in FFT.cpp class FFTMulTabs; struct FFTMulTabsDeleterPolicy { static void deleter(FFTMulTabs *p); }; class zz_pInfoT; // forward reference, defined in lzz_p.h struct FFTPrimeInfo { long q; // the prime itself mulmod_t qinv; // 1/((wide_double) q) -- but subject to change!! double qrecip; // 1/double(q) SmartPtr zz_p_context; // pointer to corresponding zz_p context, which points back to this // object in the case of a non-user FFT prime Vec RootTable[2]; // RootTable[0][j] = w^{2^{MaxRoot-j}}, // where w is a primitive 2^MaxRoot root of unity // for q // RootInvTable[1][j] = 1/RootTable[0][j] mod q Vec TwoInvTable; // TwoInvTable[j] = 1/2^j mod q Vec TwoInvPreconTable; // mulmod preconditioning data UniquePtr< FFTMulTabs, FFTMulTabsDeleterPolicy > bigtab; }; void InitFFTPrimeInfo(FFTPrimeInfo& info, long q, long w, long bigtab_index); #define NTL_MAX_FFTPRIMES (20000) // for a thread-safe implementation, it is most convenient to // impose a reasonabel upper bound on he number of FFT primes. // without this restriction, a growing table would have to be // relocated in one thread, leaving dangling pointers in // another thread. Each entry in the table is just a poiner, // so this does not incur too much space overhead. // One could alo implement a 2D-table, which would allocate // rows on demand, thus reducing wasted space at the price // of extra arithmetic to actually index into the table. // This may be an option to consider at some point. // At the current setting of 20000, on 64-bit machines with 50-bit // FFT primes, this allows for polynomials with 20*50/2 = 500K-bit // coefficients, while the table itself takes 160KB. typedef LazyTable FFTTablesType; extern FFTTablesType FFTTables; // a truly GLOBAL variable, shared among all threads inline long GetFFTPrime(long i) { return FFTTables[i]->q; } inline mulmod_t GetFFTPrimeInv(long i) { return FFTTables[i]->qinv; } inline double GetFFTPrimeRecip(long i) { return FFTTables[i]->qrecip; } long CalcMaxRoot(long p); // calculates max power of two supported by this FFT prime. void UseFFTPrime(long index); // allocates and initializes information for FFT prime void new_fft(long* A, const long* a, long k, const FFTPrimeInfo& info, long yn, long xn); inline void new_fft(long* A, const long* a, long k, const FFTPrimeInfo& info) { new_fft(A, a, k, info, 1L << k, 1L << k); } void new_ifft(long* A, const long* a, long k, const FFTPrimeInfo& info, long yn); inline void new_ifft(long* A, const long* a, long k, const FFTPrimeInfo& info) { new_ifft(A, a, k, info, 1L << k); } void new_fft_flipped(long* A, const long* a, long k, const FFTPrimeInfo& info); void new_ifft_flipped(long* A, const long* a, long k, const FFTPrimeInfo& info); inline void FFTFwd(long* A, const long *a, long k, const FFTPrimeInfo& info) { new_fft(A, a, k, info); } inline void FFTFwd_trunc(long* A, const long *a, long k, const FFTPrimeInfo& info, long yn, long xn) { new_fft(A, a, k, info, yn, xn); } inline void FFTFwd_trans(long* A, const long *a, long k, const FFTPrimeInfo& info) { new_ifft_flipped(A, a, k, info); } inline void FFTFwd(long* A, const long *a, long k, long i) // Slightly higher level interface...using the ith FFT prime { FFTFwd(A, a, k, *FFTTables[i]); } inline void FFTFwd_trunc(long* A, const long *a, long k, long i, long yn, long xn) // Slightly higher level interface...using the ith FFT prime { FFTFwd_trunc(A, a, k, *FFTTables[i], yn, xn); } inline void FFTFwd_trans(long* A, const long *a, long k, long i) // Slightly higher level interface...using the ith FFT prime { FFTFwd_trans(A, a, k, *FFTTables[i]); } inline void FFTRev1(long* A, const long *a, long k, const FFTPrimeInfo& info) { new_ifft(A, a, k, info); } inline void FFTRev1_trunc(long* A, const long *a, long k, const FFTPrimeInfo& info, long yn) { new_ifft(A, a, k, info, yn); } inline void FFTRev1_trans(long* A, const long *a, long k, const FFTPrimeInfo& info) { new_fft_flipped(A, a, k, info); } inline void FFTRev1(long* A, const long *a, long k, long i) // Slightly higher level interface...using the ith FFT prime { FFTRev1(A, a, k, *FFTTables[i]); } inline void FFTRev1_trunc(long* A, const long *a, long k, long i, long yn) // Slightly higher level interface...using the ith FFT prime { FFTRev1_trunc(A, a, k, *FFTTables[i], yn); } inline void FFTRev1_trans(long* A, const long *a, long k, long i) // Slightly higher level interface...using the ith FFT prime { FFTRev1_trans(A, a, k, *FFTTables[i]); } long IsFFTPrime(long n, long& w); // tests if n is an "FFT prime" and returns corresponding root NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/FFT_impl.h0000644417616742025610000000263714064716022020056 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_FFT_impl__H #define NTL_FFT_impl__H #include NTL_OPEN_NNS #ifdef NTL_ENABLE_AVX_FFT #if (!defined(NTL_HAVE_AVX512F) && !(defined(NTL_HAVE_AVX2) && defined(NTL_HAVE_FMA))) #error "NTL_ENABLE_AVX_FFT: not supported on this platform" #endif #if (defined(NTL_HAVE_AVX512F) && !defined(NTL_AVOID_AVX512)) #define NTL_LG2_PDSZ (3) #else #define NTL_LG2_PDSZ (2) #endif #define NTL_FFT_RDUP (NTL_LG2_PDSZ+3) #define NTL_PDSZ (1 << NTL_LG2_PDSZ) #else #define NTL_FFT_RDUP (4) // Currently, this should be at least 2 to support // loop unrolling in the FFT implementation #endif inline long FFTRoundUp(long xn, long k) // Assumes k >= 0. // Returns an integer m such that 1 <= m <= n = 2^k and // m divsisible my 2^NTL_FFT_RDUP. // Also, if xn <= n, then m >= xn. { long n = 1L << k; if (xn <= 0) xn = 1; xn = ((xn+((1L << NTL_FFT_RDUP)-1)) >> NTL_FFT_RDUP) << NTL_FFT_RDUP; if (k >= 10) { if (xn > n - (n >> 4)) xn = n; } else { if (xn > n - (n >> 3)) xn = n; } // truncation just a bit below n does not really help // at all, and can sometimes slow things down slightly, so round up // to n. This also takes care of cases where xn > n. // Actually, for smallish n, we should round up sooner, // at n-n/8, and for larger n, we should round up later, // at n-m/16. At least, experimentally, this is what I see. return xn; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/FacVec.h0000644417616742025610000000044014064716022017533 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_FacVec__H #define NTL_FacVec__H #include NTL_OPEN_NNS struct IntFactor { long q; long a; long val; long link; }; typedef Vec vec_IntFactor; typedef vec_IntFactor FacVec; void FactorInt(FacVec& fvec, long n); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2.h0000644417616742025610000002326114064716022016770 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_GF2__H #define NTL_GF2__H #include #include NTL_OPEN_NNS // Context, Bak, and Push types, just for consistency. // They don't do anything class GF2Context { public: GF2Context() {} explicit GF2Context(long p) { if (p != 2) LogicError("GF2Context with p != 2"); } void save() {} void restore() const {} }; class GF2Bak { public: void save(); void restore(); private: GF2Bak(const GF2Bak&); // disabled void operator=(const GF2Bak&); // disabled }; class GF2Push { GF2Push(const GF2Push&); // disabled void operator=(const GF2Push&); // disabled public: GF2Push() { } explicit GF2Push(const GF2Context& context) { } explicit GF2Push(long p) { if (p != 2) LogicError("GF2Push with p != 2"); } }; class GF2X; // forward declaration class ref_GF2; // forward declaration class GF2 { public: typedef long rep_type; typedef GF2Context context_type; typedef GF2Bak bak_type; typedef GF2Push push_type; typedef GF2X poly_type; unsigned long _GF2__rep; GF2() : _GF2__rep(0) { } explicit GF2(long a) : _GF2__rep(0) { *this = a; } GF2(INIT_VAL_TYPE, long a) : _GF2__rep(a & 1) { } GF2(INIT_LOOP_HOLE_TYPE, unsigned long a) : _GF2__rep(a) { } inline GF2(const ref_GF2&); GF2& operator=(long a) { _GF2__rep = a & 1; return *this; } static long modulus() { return 2; } static GF2 zero() { return GF2(); } // for consistency GF2(INIT_NO_ALLOC_TYPE) : _GF2__rep(0) { } GF2(INIT_ALLOC_TYPE) : _GF2__rep(0) { } void allocate() { } void swap(GF2& x) { GF2 t; t = *this; *this = x; x = t; } }; NTL_DECLARE_RELOCATABLE((GF2*)) class ref_GF2 { public: unsigned long *_ref_GF2__ptr; long _ref_GF2__pos; ref_GF2() : _ref_GF2__ptr(0), _ref_GF2__pos(0) { } ref_GF2(GF2& a) : _ref_GF2__ptr(&a._GF2__rep), _ref_GF2__pos(0) { } ref_GF2(INIT_LOOP_HOLE_TYPE, unsigned long *ptr, long pos) : _ref_GF2__ptr(ptr), _ref_GF2__pos(pos) { } ref_GF2 operator=(const ref_GF2& a) { unsigned long rval = (*a._ref_GF2__ptr >> a._ref_GF2__pos) & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } ref_GF2 operator=(const GF2& a) { unsigned long rval = (a._GF2__rep) & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } ref_GF2 operator=(long a) { unsigned long rval = a & 1; unsigned long lval = *_ref_GF2__ptr; lval = (lval & ~(1UL << _ref_GF2__pos)) | (rval << _ref_GF2__pos); *_ref_GF2__ptr = lval; return *this; } void swap(ref_GF2 x) { GF2 t; t = *this; *this = x; x = t; } }; // I changed the conversion from a ref_GF2 operator // to a GF2 constructor, because clang was giving me errors // Note that gcc, icc, and MS compilers were all OK with // the old code inline GF2::GF2(const ref_GF2& other) : _GF2__rep((*other._ref_GF2__ptr >> other._ref_GF2__pos) & 1) { } // functions inline long rep(GF2 a) { return a._GF2__rep; } inline long IsZero(GF2 a) { return a._GF2__rep == 0; } inline long IsOne(GF2 a) { return a._GF2__rep == 1; } inline GF2 to_GF2(long a) { return GF2(INIT_VAL, a); } inline GF2 to_GF2(const ZZ& a) { return GF2(INIT_LOOP_HOLE, IsOdd(a)); } inline GF2 operator+(GF2 a, GF2 b) { return GF2(INIT_LOOP_HOLE, a._GF2__rep ^ b._GF2__rep); } inline GF2 operator+(GF2 a, long b) { return a + to_GF2(b); } inline GF2 operator+(long a, GF2 b) { return to_GF2(a) + b; } inline GF2 operator-(GF2 a, GF2 b) { return a + b; } inline GF2 operator-(GF2 a, long b) { return a + b; } inline GF2 operator-(long a, GF2 b) { return a + b; } inline GF2 operator-(GF2 a) { return a; } inline GF2 sqr(GF2 a) { return a; } inline GF2 operator*(GF2 a, GF2 b) { return GF2(INIT_LOOP_HOLE, a._GF2__rep & b._GF2__rep); } inline GF2 operator*(GF2 a, long b) { return a * to_GF2(b); } inline GF2 operator*(long a, GF2 b) { return to_GF2(a) * b; } inline GF2 operator/(GF2 a, GF2 b) { if (IsZero(b)) ArithmeticError("GF2: division by zero"); return a; } inline GF2 operator/(GF2 a, long b) { return a / to_GF2(b); } inline GF2 operator/(long a, GF2 b) { return to_GF2(a) / b; } inline GF2 inv(GF2 a) { return 1 / a; } inline long operator==(GF2 a, GF2 b) { return a._GF2__rep == b._GF2__rep; } inline long operator==(GF2 a, long b) { return a == to_GF2(b); } inline long operator==(long a, GF2 b) { return to_GF2(a) == b; } inline long operator!=(GF2 a, GF2 b) { return !(a == b); } inline long operator!=(GF2 a, long b) { return !(a == b); } inline long operator!=(long a, GF2 b) { return !(a == b); } GF2 power(GF2 a, long e); inline GF2 random_GF2() { return GF2(INIT_LOOP_HOLE, RandomBnd(2)); } // procedural versions inline GF2& operator+=(GF2& x, GF2 b) { return x = x + b; } inline GF2& operator+=(GF2& x, long b) { return x = x + b; } inline GF2& operator-=(GF2& x, GF2 b) { return x = x - b; } inline GF2& operator-=(GF2& x, long b) { return x = x - b; } inline GF2& operator++(GF2& x) { return x = x + 1; } inline void operator++(GF2& x, int) { x = x + 1; } inline GF2& operator--(GF2& x) { return x = x - 1; } inline void operator--(GF2& x, int) { x = x - 1; } inline GF2& operator*=(GF2& x, GF2 b) { return x = x * b; } inline GF2& operator*=(GF2& x, long b) { return x = x * b; } inline GF2& operator/=(GF2& x, GF2 b) { return x = x / b; } inline GF2& operator/=(GF2& x, long b) { return x = x / b; } inline void conv(GF2& x, long a) { x = to_GF2(a); } inline void conv(GF2& x, const ZZ& a) { x = to_GF2(a); } inline void clear(GF2& x) { x = 0; } inline void set(GF2& x) { x = 1; } inline void swap(GF2& x, GF2& y) { x.swap(y); } inline void add(GF2& x, GF2 a, GF2 b) { x = a + b; } inline void sub(GF2& x, GF2 a, GF2 b) { x = a - b; } inline void negate(GF2& x, GF2 a) { x = -a; } inline void add(GF2& x, GF2 a, long b) { x = a + b; } inline void add(GF2& x, long a, GF2 b) { x = a + b; } inline void sub(GF2& x, GF2 a, long b) { x = a - b; } inline void sub(GF2& x, long a, GF2 b) { x = a - b; } inline void mul(GF2& x, GF2 a, GF2 b) { x = a * b; } inline void mul(GF2& x, GF2 a, long b) { x = a * b; } inline void mul(GF2& x, long a, GF2 b) { x = a * b; } inline void sqr(GF2& x, GF2 a) { x = sqr(a); } inline void div(GF2& x, GF2 a, GF2 b) { x = a / b; } inline void div(GF2& x, long a, GF2 b) { x = a / b; } inline void div(GF2& x, GF2 a, long b) { x = a / b; } inline void inv(GF2& x, GF2 a) { x = inv(a); } inline void power(GF2& x, GF2 a, long e) { x = power(a, e); } inline void random(GF2& x) { x = random_GF2(); } // ref_GF2 variants...theoretically, these would // have sufficed, because of the implicit conversion // from GF2& to ref_GF2, but it may be a bit more efficient // to explicitly overload everything. Moreover, // the return types of the += type operators would // not be right. inline ref_GF2 operator+=(ref_GF2 x, GF2 b) { return x = x + b; } inline ref_GF2 operator+=(ref_GF2 x, long b) { return x = x + b; } inline ref_GF2 operator-=(ref_GF2 x, GF2 b) { return x = x - b; } inline ref_GF2 operator-=(ref_GF2 x, long b) { return x = x - b; } inline ref_GF2 operator++(ref_GF2 x) { return x = x + 1; } inline void operator++(ref_GF2 x, int) { x = x + 1; } inline ref_GF2 operator--(ref_GF2 x) { return x = x - 1; } inline void operator--(ref_GF2 x, int) { x = x - 1; } inline ref_GF2 operator*=(ref_GF2 x, GF2 b) { return x = x * b; } inline ref_GF2 operator*=(ref_GF2 x, long b) { return x = x * b; } inline ref_GF2 operator/=(ref_GF2 x, GF2 b) { return x = x / b; } inline ref_GF2 operator/=(ref_GF2 x, long b) { return x = x / b; } inline void conv(ref_GF2 x, long a) { x = to_GF2(a); } inline void conv(ref_GF2 x, const ZZ& a) { x = to_GF2(a); } inline void clear(ref_GF2 x) { x = 0; } inline void set(ref_GF2 x) { x = 1; } inline void swap(ref_GF2 x, ref_GF2 y) { x.swap(y); } inline void add(ref_GF2 x, GF2 a, GF2 b) { x = a + b; } inline void sub(ref_GF2 x, GF2 a, GF2 b) { x = a - b; } inline void negate(ref_GF2 x, GF2 a) { x = -a; } inline void add(ref_GF2 x, GF2 a, long b) { x = a + b; } inline void add(ref_GF2 x, long a, GF2 b) { x = a + b; } inline void sub(ref_GF2 x, GF2 a, long b) { x = a - b; } inline void sub(ref_GF2 x, long a, GF2 b) { x = a - b; } inline void mul(ref_GF2 x, GF2 a, GF2 b) { x = a * b; } inline void mul(ref_GF2 x, GF2 a, long b) { x = a * b; } inline void mul(ref_GF2 x, long a, GF2 b) { x = a * b; } inline void sqr(ref_GF2 x, GF2 a) { x = sqr(a); } inline void div(ref_GF2 x, GF2 a, GF2 b) { x = a / b; } inline void div(ref_GF2 x, long a, GF2 b) { x = a / b; } inline void div(ref_GF2 x, GF2 a, long b) { x = a / b; } inline void inv(ref_GF2 x, GF2 a) { x = inv(a); } inline void power(ref_GF2 x, GF2 a, long e) { x = power(a, e); } inline void random(ref_GF2 x) { x = random_GF2(); } // I/O...for input, we only provide the ref_GF2 variant NTL_SNS ostream& operator<<(NTL_SNS ostream& s, GF2 a); NTL_SNS istream& operator>>(NTL_SNS istream& s, ref_GF2 x); /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, GF2 a) { conv(x, rep(a)); } inline void conv(unsigned int& x, GF2 a) { conv(x, rep(a)); } inline void conv(long& x, GF2 a) { conv(x, rep(a)); } inline void conv(unsigned long& x, GF2 a) { conv(x, rep(a)); } inline void conv(ZZ& x, GF2 a) { conv(x, rep(a)); } inline void conv(GF2& x, GF2 a) { x = a; } inline void conv(ref_GF2 x, GF2 a) { x = a; } /* ------------------------------------- */ // Finally, we declare an specialization Vec: template<> class Vec; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2E.h0000644417616742025610000002704314064716022017077 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_GF2E__H #define NTL_GF2E__H #include #include #include NTL_OPEN_NNS class GF2EInfoT { private: GF2EInfoT(); // disabled GF2EInfoT(const GF2EInfoT&); // disabled void operator=(const GF2EInfoT&); // disabled public: GF2EInfoT(const GF2X& NewP); GF2XModulus p; long KarCross; long ModCross; long DivCross; long GCDCross; long _card_exp; Lazy _card; }; extern NTL_CHEAP_THREAD_LOCAL GF2EInfoT *GF2EInfo; // info for current modulus, initially null // fast TLS access class GF2EContext { private: SmartPtr ptr; public: GF2EContext() { } explicit GF2EContext(const GF2X& p) : ptr(MakeSmart(p)) { } // copy constructor, assignment, destructor: default void save(); void restore() const; }; class GF2EBak { private: GF2EContext c; bool MustRestore; GF2EBak(const GF2EBak&); // disabled void operator=(const GF2EBak&); // disabled public: void save(); void restore(); GF2EBak() : MustRestore(false) { } ~GF2EBak(); }; class GF2EPush { private: GF2EBak bak; GF2EPush(const GF2EPush&); // disabled void operator=(const GF2EPush&); // disabled public: GF2EPush() { bak.save(); } explicit GF2EPush(const GF2EContext& context) { bak.save(); context.restore(); } explicit GF2EPush(const GF2X& p) { bak.save(); GF2EContext c(p); c.restore(); } }; class GF2EX; // forward declaration class GF2E { public: typedef GF2X rep_type; typedef GF2EContext context_type; typedef GF2EBak bak_type; typedef GF2EPush push_type; typedef GF2EX poly_type; GF2X _GF2E__rep; // ****** constructors and assignment GF2E() { } // NO_ALLOC explicit GF2E(long a) { *this = a; } // NO_ALLOC explicit GF2E(GF2 a) { *this = a; } // NO_ALLOC GF2E(GF2E& x, INIT_TRANS_TYPE) : _GF2E__rep(x._GF2E__rep, INIT_TRANS) { } GF2E(INIT_NO_ALLOC_TYPE) { } // allocates no space GF2E(INIT_ALLOC_TYPE) { _GF2E__rep.xrep.SetMaxLength(GF2E::WordLength()); } // allocates space void allocate() { _GF2E__rep.xrep.SetMaxLength(GF2E::WordLength()); } inline GF2E& operator=(long a); inline GF2E& operator=(GF2 a); // You can always access the _GF2E__representation directly...if you dare. GF2X& LoopHole() { return _GF2E__rep; } void swap(GF2E& y) { _GF2E__rep.swap(y._GF2E__rep); } static long WordLength() { return GF2EInfo->p.WordLength(); } static long storage() { return WV_storage(GF2E::WordLength()); } static const GF2XModulus& modulus() { return GF2EInfo->p; } static long KarCross() { return GF2EInfo->KarCross; } static long ModCross() { return GF2EInfo->ModCross; } static long DivCross() { return GF2EInfo->DivCross; } static long GCDCross() { return GF2EInfo->GCDCross; } static long degree() { return GF2EInfo->p.n; } static const GF2E& zero(); static const ZZ& cardinality(); static void init(const GF2X& NewP); }; NTL_DECLARE_RELOCATABLE((GF2E*)) // read-only access to GF2E representation inline const GF2X& rep(const GF2E& a) { return a._GF2E__rep; } inline void clear(GF2E& x) // x = 0 { clear(x._GF2E__rep); } inline void set(GF2E& x) // x = 1 { set(x._GF2E__rep); } inline void swap(GF2E& x, GF2E& y) // swap x and y { x.swap(y); } // ****** addition inline void add(GF2E& x, const GF2E& a, const GF2E& b) { add(x._GF2E__rep, a._GF2E__rep, b._GF2E__rep); } inline void add(GF2E& x, const GF2E& a, GF2 b) { add(x._GF2E__rep, a._GF2E__rep, b); } inline void add(GF2E& x, const GF2E& a, long b) { add(x._GF2E__rep, a._GF2E__rep, b); } inline void add(GF2E& x, GF2 a, const GF2E& b) { add(x, b, a); } inline void add(GF2E& x, long a, const GF2E& b) { add(x, b, a); } inline void sub(GF2E& x, const GF2E& a, const GF2E& b) { add(x, a, b); } inline void sub(GF2E& x, const GF2E& a, GF2 b) { add(x, a, b); } inline void sub(GF2E& x, const GF2E& a, long b) { add(x, a, b); } inline void sub(GF2E& x, GF2 a, const GF2E& b) { add(x, a, b); } inline void sub(GF2E& x, long a, const GF2E& b) { add(x, a, b); } inline void negate(GF2E& x, const GF2E& a) { x = a; } inline GF2E operator+(const GF2E& a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(const GF2E& a, GF2 b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(const GF2E& a, long b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(GF2 a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator+(long a, const GF2E& b) { GF2E x; add(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, GF2 b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a, long b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(GF2 a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(long a, const GF2E& b) { GF2E x; sub(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator-(const GF2E& a) { GF2E x; negate(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator+=(GF2E& x, const GF2E& b) { add(x, x, b); return x; } inline GF2E& operator+=(GF2E& x, GF2 b) { add(x, x, b); return x; } inline GF2E& operator+=(GF2E& x, long b) { add(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, const GF2E& b) { sub(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, GF2 b) { sub(x, x, b); return x; } inline GF2E& operator-=(GF2E& x, long b) { sub(x, x, b); return x; } inline GF2E& operator++(GF2E& x) { add(x, x, 1); return x; } inline void operator++(GF2E& x, int) { add(x, x, 1); } inline GF2E& operator--(GF2E& x) { sub(x, x, 1); return x; } inline void operator--(GF2E& x, int) { sub(x, x, 1); } // ****** multiplication inline void mul(GF2E& x, const GF2E& a, const GF2E& b) // x = a*b { MulMod(x._GF2E__rep, a._GF2E__rep, b._GF2E__rep, GF2E::modulus()); } inline void sqr(GF2E& x, const GF2E& a) // x = a^2 { SqrMod(x._GF2E__rep, a._GF2E__rep, GF2E::modulus()); } inline GF2E sqr(const GF2E& a) { GF2E x; sqr(x, a); NTL_OPT_RETURN(GF2E, x); } inline void mul(GF2E& x, const GF2E& a, GF2 b) { mul(x._GF2E__rep, a._GF2E__rep, b); } inline void mul(GF2E& x, const GF2E& a, long b) { mul(x._GF2E__rep, a._GF2E__rep, b); } inline void mul(GF2E& x, GF2 a, const GF2E& b) { mul(x, b, a); } inline void mul(GF2E& x, long a, const GF2E& b) { mul(x, b, a); } inline GF2E operator*(const GF2E& a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(const GF2E& a, GF2 b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(const GF2E& a, long b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(GF2 a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator*(long a, const GF2E& b) { GF2E x; mul(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator*=(GF2E& x, const GF2E& b) { mul(x, x, b); return x; } inline GF2E& operator*=(GF2E& x, GF2 b) { mul(x, x, b); return x; } inline GF2E& operator*=(GF2E& x, long b) { mul(x, x, b); return x; } // ****** division void div(GF2E& x, const GF2E& a, const GF2E& b); void inv(GF2E& x, const GF2E& a); inline GF2E inv(const GF2E& a) { GF2E x; inv(x, a); NTL_OPT_RETURN(GF2E, x); } inline void div(GF2E& x, const GF2E& a, GF2 b) { div(x._GF2E__rep, a._GF2E__rep, b); } inline void div(GF2E& x, const GF2E& a, long b) { div(x._GF2E__rep, a._GF2E__rep, b); } void div(GF2E& x, GF2 a, const GF2E& b); void div(GF2E& x, long a, const GF2E& b); inline GF2E operator/(const GF2E& a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(const GF2E& a, GF2 b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(const GF2E& a, long b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(GF2 a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E operator/(long a, const GF2E& b) { GF2E x; div(x, a, b); NTL_OPT_RETURN(GF2E, x); } inline GF2E& operator/=(GF2E& x, const GF2E& b) { div(x, x, b); return x; } inline GF2E& operator/=(GF2E& x, GF2 b) { div(x, x, b); return x; } inline GF2E& operator/=(GF2E& x, long b) { div(x, x, b); return x; } // ****** exponentiation inline void power(GF2E& x, const GF2E& a, const ZZ& e) { PowerMod(x._GF2E__rep, a._GF2E__rep, e, GF2E::modulus()); } inline GF2E power(const GF2E& a, const ZZ& e) { GF2E x; power(x, a, e); NTL_OPT_RETURN(GF2E, x); } inline void power(GF2E& x, const GF2E& a, long e) { PowerMod(x._GF2E__rep, a._GF2E__rep, e, GF2E::modulus()); } inline GF2E power(const GF2E& a, long e) { GF2E x; power(x, a, e); NTL_OPT_RETURN(GF2E, x); } // ****** conversion inline void conv(GF2E& x, const GF2X& a) // x = (a mod p) { rem(x._GF2E__rep, a, GF2E::modulus()); } inline void conv(GF2E& x, long a) { conv(x._GF2E__rep, a); } inline void conv(GF2E& x, GF2 a) { conv(x._GF2E__rep, a); } inline void conv(GF2E& x, const ZZ& a) { conv(x._GF2E__rep, a); } inline GF2E to_GF2E(const GF2X& a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(long a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(GF2 a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } inline GF2E to_GF2E(const ZZ& a) { GF2E x; conv(x, a); NTL_OPT_RETURN(GF2E, x); } // ****** comparison inline long IsZero(const GF2E& a) { return IsZero(a._GF2E__rep); } inline long IsOne(const GF2E& a) { return IsOne(a._GF2E__rep); } inline long operator==(const GF2E& a, const GF2E& b) { return a._GF2E__rep == b._GF2E__rep; } inline long operator==(const GF2E& a, GF2 b) { return a._GF2E__rep == b; } inline long operator==(const GF2E& a, long b) { return a._GF2E__rep == b; } inline long operator==(const GF2 a, const GF2E& b) { return a == b._GF2E__rep; } inline long operator==(const long a, const GF2E& b) { return a == b._GF2E__rep; } inline long operator!=(const GF2E& a, const GF2E& b) { return !(a == b); } inline long operator!=(const GF2E& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2E& a, long b) { return !(a == b); } inline long operator!=(GF2 a, const GF2E& b) { return !(a == b); } inline long operator!=(long a, const GF2E& b) { return !(a == b); } // ****** trace inline void trace(ref_GF2 x, const GF2E& a) { TraceMod(x, a._GF2E__rep, GF2E::modulus()); } inline GF2 trace(const GF2E& a) { return TraceMod(a._GF2E__rep, GF2E::modulus()); } // ****** random numbers inline void random(GF2E& x) // x = random element in GF2E { random(x._GF2E__rep, GF2EInfo->p.n); } inline GF2E random_GF2E() { GF2E x; random(x); NTL_OPT_RETURN(GF2E, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2E& a) { return s << a._GF2E__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, GF2E& x); inline GF2E& GF2E::operator=(long a) { conv(*this, a); return *this; } inline GF2E& GF2E::operator=(GF2 a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2X& x, const GF2E& a) { x = rep(a); } inline void conv(GF2E& x, const GF2E& a) { x = a; } /* ------------------------------------- */ // overload these functions for Vec. // They are defined in vec_GF2E.c void BlockConstruct(GF2E* p, long n); void BlockConstructFromVec(GF2E* p, long n, const GF2E* q); void BlockConstructFromObj(GF2E* p, long n, const GF2E& q); void BlockDestroy(GF2E* p, long n); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2EX.h0000644417616742025610000007406014064716022017230 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_GF2EX__H #define NTL_GF2EX__H #include #include #include #include #include #include NTL_OPEN_NNS class GF2EXModulus; // forward declaration class GF2EX { public: typedef GF2E coeff_type; typedef GF2EXModulus modulus_type; vec_GF2E rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ GF2EX() { } explicit GF2EX(long a) { *this = a; } explicit GF2EX(GF2 a) { *this = a; } explicit GF2EX(const GF2& a) { *this = a; } GF2EX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } // default copy constructor and assignment // default destructor void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } GF2E& operator[](long i) { return rep[i]; } const GF2E& operator[](long i) const { return rep[i]; } static const GF2EX& zero(); inline GF2EX& operator=(long a); inline GF2EX& operator=(GF2 a); inline GF2EX& operator=(const GF2E& a); inline GF2EX(long i, long a); inline GF2EX(long i, GF2 a); inline GF2EX(long i, const GF2E& a); inline GF2EX(INIT_MONO_TYPE, long i, long a); inline GF2EX(INIT_MONO_TYPE, long i, GF2 a); inline GF2EX(INIT_MONO_TYPE, long i, const GF2E& a); inline GF2EX(INIT_MONO_TYPE, long i); GF2EX(GF2EX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } void swap(GF2EX& x) { rep.swap(x.rep); } }; NTL_DECLARE_RELOCATABLE((GF2EX*)) /******************************************************************** input and output *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, GF2EX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2EX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const GF2EX& a) { return a.rep.length() - 1; } const GF2E& coeff(const GF2EX& a, long i); // zero if i not in range void GetCoeff(GF2E& x, const GF2EX& a, long i); // x = a[i], or zero if i not in range const GF2E& LeadCoeff(const GF2EX& a); // zero if a == 0 const GF2E& ConstTerm(const GF2EX& a); // zero if a == 0 void SetCoeff(GF2EX& x, long i, const GF2E& a); void SetCoeff(GF2EX& x, long i, GF2 a); void SetCoeff(GF2EX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(GF2EX& x, long i); // x[i] = 1, error is raised if i < 0 inline GF2EX::GF2EX(long i, const GF2E& a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(long i, long a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, const GF2E& a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline GF2EX::GF2EX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(GF2EX& x); // x is set to the monomial X long IsX(const GF2EX& a); // test if x = X inline void clear(GF2EX& x) // x = 0 { x.rep.SetLength(0); } inline void set(GF2EX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(GF2EX& x, GF2EX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void random(GF2EX& x, long n); inline GF2EX random_GF2EX(long n) { GF2EX x; random(x, n); NTL_OPT_RETURN(GF2EX, x); } // generate a random polynomial of degree < n void trunc(GF2EX& x, const GF2EX& a, long m); inline GF2EX trunc(const GF2EX& a, long m) { GF2EX x; trunc(x, a, m); NTL_OPT_RETURN(GF2EX, x); } // x = a % X^m void RightShift(GF2EX& x, const GF2EX& a, long n); inline GF2EX RightShift(const GF2EX& a, long n) { GF2EX x; RightShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a/X^n void LeftShift(GF2EX& x, const GF2EX& a, long n); inline GF2EX LeftShift(const GF2EX& a, long n) { GF2EX x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline GF2EX operator>>(const GF2EX& a, long n) { GF2EX x; RightShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator<<(const GF2EX& a, long n) { GF2EX x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator<<=(GF2EX& x, long n) { LeftShift(x, x, n); return x; } inline GF2EX& operator>>=(GF2EX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(GF2EX& x, const GF2EX& a); inline GF2EX diff(const GF2EX& a) { GF2EX x; diff(x, a); NTL_OPT_RETURN(GF2EX, x); } // x = derivative of a void MakeMonic(GF2EX& x); void reverse(GF2EX& c, const GF2EX& a, long hi); inline GF2EX reverse(const GF2EX& a, long hi) { GF2EX x; reverse(x, a, hi); NTL_OPT_RETURN(GF2EX, x); } inline void reverse(GF2EX& c, const GF2EX& a) { reverse(c, a, deg(a)); } inline GF2EX reverse(const GF2EX& a) { GF2EX x; reverse(x, a); NTL_OPT_RETURN(GF2EX, x); } inline void VectorCopy(vec_GF2E& x, const GF2EX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_GF2E VectorCopy(const GF2EX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(GF2EX& x, long a); void conv(GF2EX& x, GF2 a); void conv(GF2EX& x, const GF2E& a); void conv(GF2EX& x, const ZZ& a); #ifndef NTL_TRANSITION void conv(GF2EX& x, const GF2X& a); #endif void conv(GF2EX& x, const vec_GF2E& a); inline GF2EX to_GF2EX(long a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(GF2 a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(const GF2E& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX to_GF2EX(const ZZ& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } #ifndef NTL_TRANSITION inline GF2EX to_GF2EX(const GF2X& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } #endif inline GF2EX to_GF2EX(const vec_GF2E& a) { GF2EX x; conv(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& GF2EX::operator=(const GF2E& a) { conv(*this, a); return *this; } inline GF2EX& GF2EX::operator=(GF2 a) { conv(*this, a); return *this; } inline GF2EX& GF2EX::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2EX& x, const GF2EX& a) { x = a; } inline void conv(vec_GF2E& x, const GF2EX& a) { x = a.rep; } class ZZX; void conv(GF2EX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const GF2EX& a); long IsOne(const GF2EX& a); inline long operator==(const GF2EX& a, const GF2EX& b) { return a.rep == b.rep; } long operator==(const GF2EX& a, const GF2E& b); long operator==(const GF2EX& a, GF2 b); long operator==(const GF2EX& a, long b); inline long operator==(const GF2E& a, const GF2EX& b) { return b == a; } inline long operator==(GF2 a, const GF2EX& b) { return b == a; } inline long operator==(long a, const GF2EX& b) { return b == a; } inline long operator!=(const GF2EX& a, const GF2EX& b) { return !(a == b); } inline long operator!=(const GF2EX& a, const GF2E& b) { return !(a == b); } inline long operator!=(const GF2EX& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2EX& a, long b) { return !(a == b); } inline long operator!=(const GF2E& a, const GF2EX& b) { return !(a == b); } inline long operator!=(GF2 a, const GF2EX& b) { return !(a == b); } inline long operator!=(long a, const GF2EX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b void add(GF2EX& x, const GF2EX& a, const GF2E& b); void add(GF2EX& x, const GF2EX& a, GF2 b); void add(GF2EX& x, const GF2EX& a, long); inline void add(GF2EX& x, const GF2E& a, const GF2EX& b) { add(x, b, a); } inline void add(GF2EX& x, GF2 a, const GF2EX& b) { add(x, b, a); } inline void add(GF2EX& x, long a, const GF2EX& b) { add(x, b, a); } inline void sub(GF2EX& x, const GF2EX& a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, const GF2E& b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, GF2 b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2EX& a, long b) { add(x, a, b); } inline void sub(GF2EX& x, const GF2E& a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, GF2 a, const GF2EX& b) { add(x, a, b); } inline void sub(GF2EX& x, long a, const GF2EX& b) { add(x, a, b); } inline void negate(GF2EX& x, const GF2EX& a) { x = a; } inline GF2EX operator+(const GF2EX& a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, const GF2E& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, GF2 b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2EX& a, long b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(const GF2E& a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(GF2 a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator+(long a, const GF2EX& b) { GF2EX x; add(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, const GF2E& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, GF2 b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2EX& a, long b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(const GF2E& a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(GF2 a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator-(long a, const GF2EX& b) { GF2EX x; sub(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator+=(GF2EX& x, const GF2EX& b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, const GF2E& b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, GF2 b) { add(x, x, b); return x; } inline GF2EX& operator+=(GF2EX& x, long b) { add(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, const GF2EX& b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, const GF2E& b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, GF2 b) { sub(x, x, b); return x; } inline GF2EX& operator-=(GF2EX& x, long b) { sub(x, x, b); return x; } inline GF2EX operator-(const GF2EX& a) { GF2EX x; negate(x, a); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator++(GF2EX& x) { add(x, x, 1); return x; } inline void operator++(GF2EX& x, int) { add(x, x, 1); } inline GF2EX& operator--(GF2EX& x) { sub(x, x, 1); return x; } inline void operator--(GF2EX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b void sqr(GF2EX& x, const GF2EX& a); inline GF2EX sqr(const GF2EX& a) { GF2EX x; sqr(x, a); NTL_OPT_RETURN(GF2EX, x); } // x = a^2 void mul(GF2EX & x, const GF2EX& a, const GF2E& b); void mul(GF2EX & x, const GF2EX& a, GF2 b); void mul(GF2EX & x, const GF2EX& a, long b); inline void mul(GF2EX& x, const GF2E& a, const GF2EX& b) { mul(x, b, a); } inline void mul(GF2EX& x, GF2 a, const GF2EX& b) { mul(x, b, a); } inline void mul(GF2EX& x, long a, const GF2EX& b) { mul(x, b, a); } void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n); inline GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n) { GF2EX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(GF2EX, x); } // x = a * b % X^n void SqrTrunc(GF2EX& x, const GF2EX& a, long n); inline GF2EX SqrTrunc(const GF2EX& a, long n) { GF2EX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(GF2EX, x); } // x = a*a % X^n inline GF2EX operator*(const GF2EX& a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, const GF2E& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, GF2 b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2EX& a, long b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(const GF2E& a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(GF2 a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator*(long a, const GF2EX& b) { GF2EX x; mul(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator*=(GF2EX& x, const GF2EX& b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, const GF2E& b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, GF2 b) { mul(x, x, b); return x; } inline GF2EX& operator*=(GF2EX& x, long b) { mul(x, x, b); return x; } void power(GF2EX& x, const GF2EX& a, long e); inline GF2EX power(const GF2EX& a, long e) { GF2EX x; power(x, a, e); NTL_OPT_RETURN(GF2EX, x); } /************************************************************* Division **************************************************************/ void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b); // q = a/b, r = a%b void div(GF2EX& q, const GF2EX& a, const GF2EX& b); void div(GF2EX& q, const GF2EX& a, const GF2E& b); void div(GF2EX& q, const GF2EX& a, GF2 b); void div(GF2EX& q, const GF2EX& a, long b); // q = a/b void rem(GF2EX& r, const GF2EX& a, const GF2EX& b); // r = a%b long divide(GF2EX& q, const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(GF2EX& x, const GF2EX& a, long m); inline GF2EX InvTrunc(const GF2EX& a, long m) { GF2EX x; InvTrunc(x, a, m); NTL_OPT_RETURN(GF2EX, x); } // computes x = a^{-1} % X^m // constant term must be non-zero inline GF2EX operator/(const GF2EX& a, const GF2EX& b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, const GF2E& b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, GF2 b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator/(const GF2EX& a, long b) { GF2EX x; div(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator/=(GF2EX& x, const GF2EX& b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, const GF2E& b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, GF2 b) { div(x, x, b); return x; } inline GF2EX& operator/=(GF2EX& x, long b) { div(x, x, b); return x; } inline GF2EX operator%(const GF2EX& a, const GF2EX& b) { GF2EX x; rem(x, a, b); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator%=(GF2EX& x, const GF2EX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b); inline GF2EX GCD(const GF2EX& a, const GF2EX& b) { GF2EX x; GCD(x, a, b); NTL_OPT_RETURN(GF2EX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the GF2EXModulus data structure and associated routines below. void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f); inline GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f) { GF2EX x; MulMod(x, a, b, f); NTL_OPT_RETURN(GF2EX, x); } // x = (a * b) % f void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX SqrMod(const GF2EX& a, const GF2EX& f) { GF2EX x; SqrMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = a^2 % f void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX MulByXMod(const GF2EX& a, const GF2EX& f) { GF2EX x; MulByXMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = (a * X) mod f void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f); inline GF2EX InvMod(const GF2EX& a, const GF2EX& f) { GF2EX x; InvMod(x, a, f); NTL_OPT_RETURN(GF2EX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build GF2EXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class GF2EXModulus { public: GF2EXModulus(); GF2EXModulus(const GF2EX& ff); GF2EX f; // the modulus operator const GF2EX& () const { return f; } const GF2EX& val() const { return f; } long n; // deg(f) long method; // GF2EX_MOD_PLAIN or GF2EX_MOD_MUL GF2EX h0; GF2E hlc; GF2EX f0; OptionalVal< Lazy > tracevec; // extra level of indirection to ensure class is relocatable }; NTL_DECLARE_RELOCATABLE((GF2EXModulus*)) inline long deg(const GF2EXModulus& F) { return F.n; } void build(GF2EXModulus& F, const GF2EX& f); void rem(GF2EX& r, const GF2EX& a, const GF2EXModulus& F); void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F); void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F); void MulMod(GF2EX& c, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); inline GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F) { GF2EX x; MulMod(x, a, b, F); NTL_OPT_RETURN(GF2EX, x); } void SqrMod(GF2EX& c, const GF2EX& a, const GF2EXModulus& F); inline GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; SqrMod(x, a, F); NTL_OPT_RETURN(GF2EX, x); } void PowerMod(GF2EX& h, const GF2EX& g, const ZZ& e, const GF2EXModulus& F); inline void PowerMod(GF2EX& h, const GF2EX& g, long e, const GF2EXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline GF2EX PowerMod(const GF2EX& g, const ZZ& e, const GF2EXModulus& F) { GF2EX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX PowerMod(const GF2EX& g, long e, const GF2EXModulus& F) { GF2EX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2EX, x); } void PowerXMod(GF2EX& hh, const ZZ& e, const GF2EXModulus& F); inline void PowerXMod(GF2EX& h, long e, const GF2EXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F) { GF2EX x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX PowerXMod(long e, const GF2EXModulus& F) { GF2EX x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX operator%(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; rem(x, a, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F) { rem(x, x, F); return x; } inline GF2EX operator/(const GF2EX& a, const GF2EXModulus& F) { GF2EX x; div(x, a, F); NTL_OPT_RETURN(GF2EX, x); } inline GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of GF2EX's *****************************************************************/ typedef Vec vec_GF2EX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(GF2EX& x, const vec_GF2E& a); inline GF2EX BuildFromRoots(const vec_GF2E& a) { GF2EX x; BuildFromRoots(x, a); NTL_OPT_RETURN(GF2EX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(GF2E& b, const GF2EX& f, const GF2E& a); inline GF2E eval(const GF2EX& f, const GF2E& a) { GF2E x; eval(x, f, a); NTL_OPT_RETURN(GF2E, x); } // b = f(a) void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a); inline vec_GF2E eval(const GF2EX& f, const vec_GF2E& a) { vec_GF2E x; eval(x, f, a); NTL_OPT_RETURN(vec_GF2E, x); } // b[i] = f(a[i]) inline void eval(GF2E& b, const GF2X& f, const GF2E& a) { conv(b, CompMod(f, rep(a), GF2E::modulus())); } inline GF2E eval(const GF2X& f, const GF2E& a) { GF2E x; eval(x, f, a); NTL_OPT_RETURN(GF2E, x); } // b = f(a) void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b); inline GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b) { GF2EX x; interpolate(x, a, b); NTL_OPT_RETURN(GF2EX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); inline GF2EX CompMod(const GF2EX& g, const GF2EX& h, const GF2EXModulus& F) { GF2EX x; CompMod(x, g, h, F); NTL_OPT_RETURN(GF2EX, x); } // x = g(h) mod f void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If GF2EXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If GF2EXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, GF2EXArgBound = 0. // If a single h is going to be used with many g's // then you should build a GF2EXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If GF2EXArgBound > 0, a table of size less than m may be built. struct GF2EXArgument { vec_GF2EX H; }; extern NTL_CHEAP_THREAD_LOCAL long GF2EXArgBound; void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); inline GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F) { GF2EX x; CompMod(x, g, H, F); NTL_OPT_RETURN(GF2EX, x); } void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m); inline GF2EX MinPolySeq(const vec_GF2E& a, long m) { GF2EX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(GF2EX, x); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F); inline GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void MinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } void ProbMinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F); inline GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void ProbMinPolyMod(GF2EX& hh, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); inline GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F) { GF2EX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(GF2EX, x); } void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m) { GF2EX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2EX, x); } struct GF2EXTransMultiplier { GF2EX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F); void TransMulMod(GF2EX& x, const GF2EX& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F); void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F); inline vec_GF2E UpdateMap(const vec_GF2E& a, const GF2EXTransMultiplier& B, const GF2EXModulus& F) { vec_GF2E x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_GF2E, x); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); inline vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F) { vec_GF2E x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2E, x); } void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); inline vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EX& H, const GF2EXModulus& F) { vec_GF2E x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2E, x); } inline void project(GF2E& x, const vec_GF2E& a, const GF2EX& b) { InnerProduct(x, a, b.rep); } inline GF2E project(const vec_GF2E& a, const GF2EX& b) { GF2E x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(GF2E, x); } /********************************************************** Modular Composition and Minimal Polynomials in towers ***********************************************************/ // composition void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F); inline GF2EX CompTower(const GF2X& g, const GF2EXArgument& A, const GF2EXModulus& F) { GF2EX x; CompTower(x, g, A, F); NTL_OPT_RETURN(GF2EX, x); } void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F); inline GF2EX CompTower(const GF2X& g, const GF2EX& h, const GF2EXModulus& F) { GF2EX x; CompTower(x, g, h, F); NTL_OPT_RETURN(GF2EX, x); } // prob min poly void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } // min poly void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { MinPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; MinPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } // irred poly void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); inline GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m) { GF2X x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } inline void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F) { IrredPolyTower(h, g, F, deg(F)*GF2E::degree()); } inline GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F) { GF2X x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(GF2X, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_GF2E& S, const GF2EX& f); inline vec_GF2E TraceVec(const GF2EX& f) { vec_GF2E x; TraceVec(x, f); NTL_OPT_RETURN(vec_GF2E, x); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F); inline GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F) { GF2E x; TraceMod(x, a, F); NTL_OPT_RETURN(GF2E, x); } void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f); inline GF2E TraceMod(const GF2EX& a, const GF2EX& f) { GF2E x; TraceMod(x, a, f); NTL_OPT_RETURN(GF2E, x); } void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f); inline GF2E NormMod(const GF2EX& a, const GF2EX& f) { GF2E x; NormMod(x, a, f); NTL_OPT_RETURN(GF2E, x); } void resultant(GF2E& rres, const GF2EX& a, const GF2EX& b); inline GF2E resultant(const GF2EX& a, const GF2EX& b) { GF2E x; resultant(x, a, b); NTL_OPT_RETURN(GF2E, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2EXFactoring.h0000644417616742025610000001542614064716022021066 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_GF2EXFactoring__H #define NTL_GF2EXFactoring__H #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f); inline vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f) { vec_pair_GF2EX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_GF2E& x, const GF2EX& f); inline vec_GF2E FindRoots(const GF2EX& f) { vec_GF2E x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(GF2E& root, const GF2EX& f); inline GF2E FindRoot(const GF2EX& f) { GF2E x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX SFBerlekamp(const GF2EX& f, long verbose=0) { vec_GF2EX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); inline vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0) { vec_pair_GF2EX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. extern NTL_CHEAP_THREAD_LOCAL long GF2EX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); inline vec_pair_GF2EX_long DDF(const GF2EX& f, const GF2EX& h, long verbose=0) { vec_pair_GF2EX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. extern NTL_CHEAP_THREAD_LOCAL long GF2EX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF extern NTL_CHEAP_THREAD_LOCAL double GF2EXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds GF2EXFileThresh KB. void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); inline vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h, long verbose=0) { vec_pair_GF2EX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& b, long d, long verbose=0); inline vec_GF2EX EDF(const GF2EX& f, const GF2EX& b, long d, long verbose=0) { vec_GF2EX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX RootEDF(const GF2EX& f, long verbose=0) { vec_GF2EX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0); inline vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0) { vec_GF2EX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); inline vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0) { vec_pair_GF2EX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(GF2EX& f, const vec_pair_GF2EX_long& v); inline GF2EX mul(const vec_pair_GF2EX_long& v) { GF2EX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const GF2EX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const GF2EX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const GF2EX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(GF2EX& f, long n); inline GF2EX BuildIrred_GF2EX(long n) { GF2EX x; BuildIrred(x, n); NTL_OPT_RETURN(GF2EX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(GF2EX& f, const GF2EX& g); inline GF2EX BuildRandomIrred(const GF2EX& g) { GF2EX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(GF2EX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F); void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b); inline GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& b) { GF2EX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F); inline GF2EX PowerCompose(const GF2EX& a, long d, const GF2EXModulus& F) { GF2EX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PlainFrobeniusMap(GF2EX& h, const GF2EXModulus& F); void ComposeFrobeniusMap(GF2EX& y, const GF2EXModulus& F); void FrobeniusMap(GF2EX& h, const GF2EXModulus& F); inline GF2EX FrobeniusMap(const GF2EXModulus& F) { GF2EX x; FrobeniusMap(x, F); return x; } long UseComposeFrobenius(long d, long n); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2X.h0000644417616742025610000005310514064716022017120 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_GF2X__H #define NTL_GF2X__H #include #include #include #include #include NTL_OPEN_NNS class GF2E; // forward declaration class GF2XModulus; class GF2X { public: typedef GF2 coeff_type; typedef GF2E residue_type; typedef GF2XModulus modulus_type; WordVector xrep; typedef vec_GF2 VectorBaseType; GF2X() { } explicit GF2X(long a) { *this = a; } explicit GF2X(GF2 a) { *this = a; } // we have to explicitly declare copy constructor and assignment // in case we also declare the corresponding move operations GF2X(const GF2X& a) : xrep(a.xrep) { } GF2X& operator=(const GF2X& a) { xrep = a.xrep; return *this; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) GF2X(GF2X&& a) NTL_FAKE_NOEXCEPT { if (a.xrep.pinned()) { *this = a; } else { xrep.unpinned_move(a.xrep); } } #ifndef NTL_DISABLE_MOVE_ASSIGN GF2X& operator=(GF2X&& a) NTL_FAKE_NOEXCEPT { if (xrep.pinned() || a.xrep.pinned()) { *this = a; } else { xrep.unpinned_move(a.xrep); } return *this; } #endif #endif GF2X(INIT_SIZE_TYPE, long n); inline GF2X& operator=(GF2 a); inline GF2X& operator=(long a); void normalize(); static const GF2X& zero(); void kill() { xrep.kill(); } void SetMaxLength(long n); void SetLength(long n); ref_GF2 operator[](long i) { #ifdef NTL_RANGE_CHECK if (i < 0) LogicError("index out of range in Vec"); long q, r; _ntl_bpl_divrem(cast_unsigned(i), q, r); if (q >= xrep.length()) LogicError("index out of range in Vec"); #endif vec_GF2::iterator t(INIT_LOOP_HOLE, xrep.elts(), i); return *t; } const GF2 operator[](long i) const { #ifdef NTL_RANGE_CHECK if (i < 0) LogicError("index out of range in Vec"); long q, r; _ntl_bpl_divrem(cast_unsigned(i), q, r); if (q >= xrep.length()) LogicError("index out of range in Vec"); #endif vec_GF2::const_iterator t(INIT_LOOP_HOLE, xrep.elts(), i); return *t; } static NTL_CHEAP_THREAD_LOCAL long HexOutput; inline GF2X(long i, GF2 c); inline GF2X(long i, long c); inline GF2X(INIT_MONO_TYPE, long i, GF2 c); inline GF2X(INIT_MONO_TYPE, long i, long c); inline GF2X(INIT_MONO_TYPE, long i); GF2X(GF2X& x, INIT_TRANS_TYPE) : xrep(x.xrep, INIT_TRANS) { } // This should only be used for simple, local variables // that are not be subject to special memory management. void swap(GF2X& x) { xrep.swap(x.xrep); } // mainly for internal consumption by GF2XWatcher void KillBig() { xrep.KillBig(); } }; NTL_DECLARE_RELOCATABLE((GF2X*)) long IsZero(const GF2X& a); long IsOne(const GF2X& a); long IsX(const GF2X& a); const GF2 coeff(const GF2X& a, long i); const GF2 LeadCoeff(const GF2X& a); const GF2 ConstTerm(const GF2X& a); inline void clear(GF2X& x) { x.xrep.ZeroLength(); } void set(GF2X& x); void SetX(GF2X& x); void SetCoeff(GF2X& x, long i); void SetCoeff(GF2X& x, long i, GF2 a); void SetCoeff(GF2X& x, long i, long a); inline GF2X::GF2X(long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(long i, long a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i, GF2 a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline GF2X::GF2X(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } inline void swap(GF2X& a, GF2X& b) { a.swap(b); } long deg(const GF2X& aa); long weight(const GF2X& a); long operator==(const GF2X& a, const GF2X& b); inline long operator!=(const GF2X& a, const GF2X& b) { return !(a == b); } long operator==(const GF2X& a, GF2 b); long operator==(const GF2X& a, long b); inline long operator==(GF2 a, const GF2X& b) { return b == a; } inline long operator==(long a, const GF2X& b) { return b == a; } inline long operator!=(const GF2X& a, GF2 b) { return !(a == b); } inline long operator!=(const GF2X& a, long b) { return !(a == b); } inline long operator!=(GF2 a, const GF2X& b) { return !(a == b); } inline long operator!=(long a, const GF2X& b) { return !(a == b); } NTL_SNS istream & operator>>(NTL_SNS istream& s, GF2X& a); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const GF2X& a); void random(GF2X& x, long n); inline GF2X random_GF2X(long n) { GF2X x; random(x, n); NTL_OPT_RETURN(GF2X, x); } void add(GF2X& x, const GF2X& a, const GF2X& b); void add(GF2X& x, const GF2X& a, GF2 b); void add(GF2X& x, const GF2X& a, long b); inline void add(GF2X& x, GF2 a, const GF2X& b) { add(x, b, a); } inline void add(GF2X& x, long a, const GF2X& b) { add(x, b, a); } inline void sub(GF2X& x, const GF2X& a, const GF2X& b) { add(x, a, b); } inline void sub(GF2X& x, const GF2X& a, GF2 b) { add(x, a, b); } inline void sub(GF2X& x, const GF2X& a, long b) { add(x, a, b); } inline void sub(GF2X& x, GF2 a, const GF2X& b) { add(x, a, b); } inline void sub(GF2X& x, long a, const GF2X& b) { add(x, a, b); } inline void negate(GF2X& x, const GF2X& a) { x = a; } inline GF2X operator+(const GF2X& a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(const GF2X& a, GF2 b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(const GF2X& a, long b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(GF2 a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator+(long a, const GF2X& b) { GF2X x; add(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, GF2 b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(const GF2X& a, long b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(GF2 a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator-(long a, const GF2X& b) { GF2X x; sub(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator+=(GF2X& x, const GF2X& b) { add(x, x, b); return x; } inline GF2X& operator+=(GF2X& x, GF2 b) { add(x, x, b); return x; } inline GF2X& operator+=(GF2X& x, long b) { add(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, const GF2X& b) { sub(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, GF2 b) { sub(x, x, b); return x; } inline GF2X& operator-=(GF2X& x, long b) { sub(x, x, b); return x; } inline GF2X operator-(const GF2X& a) { GF2X x; negate(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator++(GF2X& x) { add(x, x, 1); return x; } inline void operator++(GF2X& x, int) { add(x, x, 1); } inline GF2X& operator--(GF2X& x) { sub(x, x, 1); return x; } inline void operator--(GF2X& x, int) { sub(x, x, 1); } void mul(GF2X& c, const GF2X& a, const GF2X& b); void OldMul(GF2X& c, const GF2X& a, const GF2X& b); void mul(GF2X& x, const GF2X& a, GF2 b); void mul(GF2X& x, const GF2X& a, long b); inline void mul(GF2X& x, GF2 a, const GF2X& b) { mul(x, b, a); } inline void mul(GF2X& x, long a, const GF2X& b) { mul(x, b, a); } void MulByX(GF2X& x, const GF2X& a); inline GF2X MulByX(const GF2X& a) { GF2X x; MulByX(x, a); NTL_OPT_RETURN(GF2X, x); } void sqr(GF2X& c, const GF2X& a); inline GF2X sqr(const GF2X& a) { GF2X x; sqr(x, a); NTL_OPT_RETURN(GF2X, x); } void trunc(GF2X& x, const GF2X& a, long m); inline GF2X trunc(const GF2X& a, long m) { GF2X x; trunc(x, a, m); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, GF2 b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(const GF2X& a, long b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(GF2 a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator*(long a, const GF2X& b) { GF2X x; mul(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator*=(GF2X& x, const GF2X& b) { mul(x, x, b); return x; } inline GF2X& operator*=(GF2X& x, GF2 b) { mul(x, x, b); return x; } inline GF2X& operator*=(GF2X& x, long b) { mul(x, x, b); return x; } void power(GF2X& x, const GF2X& a, long e); // x = a^e (e >= 0) inline GF2X power(const GF2X& a, long e) { GF2X x; power(x, a, e); NTL_OPT_RETURN(GF2X, x); } typedef Vec vec_GF2X; void LeftShift(GF2X& c, const GF2X& a, long n); inline GF2X LeftShift(const GF2X& a, long n) { GF2X x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } void ShiftAdd(GF2X& c, const GF2X& a, long n); void RightShift(GF2X& c, const GF2X& a, long n); inline GF2X RightShift(const GF2X& a, long n) { GF2X x; RightShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } #ifndef NTL_TRANSITION inline GF2X operator>>(const GF2X& a, long n) { GF2X x; RightShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator<<(const GF2X& a, long n) { GF2X x; LeftShift(x, a, n); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator<<=(GF2X& x, long n) { LeftShift(x, x, n); return x; } inline GF2X& operator>>=(GF2X& x, long n) { RightShift(x, x, n); return x; } #endif void CopyReverse(GF2X& c, const GF2X& a, long hi); // c[0..hi] = reverse(a[0..hi]), with zero fill as necessary inline void reverse(GF2X& c, const GF2X& a, long hi) { CopyReverse(c, a, hi); } inline GF2X reverse(const GF2X& a, long hi) { GF2X x; reverse(x, a, hi); NTL_OPT_RETURN(GF2X, x); } inline void reverse(GF2X& c, const GF2X& a) { CopyReverse(c, a, deg(a)); } inline GF2X reverse(const GF2X& a) { GF2X x; reverse(x, a); NTL_OPT_RETURN(GF2X, x); } void InvTrunc(GF2X& c, const GF2X& a, long e); inline GF2X InvTrunc(const GF2X& a, long e) { GF2X x; InvTrunc(x, a, e); NTL_OPT_RETURN(GF2X, x); } class GF2XModulus { public: GF2XModulus(); GF2XModulus(const GF2XModulus&); GF2XModulus& operator=(const GF2XModulus&); GF2XModulus(const GF2X& ff); GF2X f; // the modulus operator const GF2X& () const { return f; } const GF2X& val() const { return f; } long n; // deg(f) long sn; // f.xrep.length() long posn; // n - NTL_BITS_PER_LONG*(sn-1); long k3; // used for trinomials and pentanomials long k2; long k1; long size; // word length of residues long WordLength() const { return size; } _ntl_ulong msk; // mask of high bits of residues long method; vec_GF2X stab; UniqueArray stab_ptr; UniqueArray stab_cnt; UniqueArray stab1; GF2X h0, f0; OptionalVal< Lazy > tracevec; }; NTL_DECLARE_RELOCATABLE((GF2XModulus*)) inline long deg(const GF2XModulus& F) { return F.n; } void build(GF2XModulus& F, const GF2X& f); void rem(GF2X& r, const GF2X& a, const GF2XModulus& F); void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F); void div(GF2X& q, const GF2X& a, const GF2XModulus& F); void PlainDivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); void PlainDiv(GF2X& q, const GF2X& a, const GF2X& b); void PlainRem(GF2X& r, const GF2X& a, const GF2X& b); void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2XModulus& F); inline GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F) { GF2X x; MulMod(x, a, b, F); NTL_OPT_RETURN(GF2X, x); } void SqrMod(GF2X& c, const GF2X& a, const GF2XModulus& F); inline GF2X SqrMod(const GF2X& a, const GF2XModulus& F) { GF2X x; SqrMod(x, a, F); NTL_OPT_RETURN(GF2X, x); } void MulByXMod(GF2X& c, const GF2X& a, const GF2XModulus& F); inline GF2X MulByXMod(const GF2X& a, const GF2XModulus& F) { GF2X x; MulByXMod(x, a, F); NTL_OPT_RETURN(GF2X, x); } void MulMod(GF2X& c, const GF2X& a, const GF2X& b, const GF2X& f); inline GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f) { GF2X x; MulMod(x, a, b, f); NTL_OPT_RETURN(GF2X, x); } void SqrMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X SqrMod(const GF2X& a, const GF2X& f) { GF2X x; SqrMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } void MulByXMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X MulByXMod(const GF2X& a, const GF2X& f) { GF2X x; MulByXMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } void InvMod(GF2X& c, const GF2X& a, const GF2X& f); inline GF2X InvMod(const GF2X& a, const GF2X& f) { GF2X x; InvMod(x, a, f); NTL_OPT_RETURN(GF2X, x); } long InvModStatus(GF2X& c, const GF2X& a, const GF2X& f); inline long InvModStatus(GF2X& c, const GF2X& a, const GF2XModulus& F) { return InvModStatus(c, a, F.f); } void PowerMod(GF2X& h, const GF2X& g, const ZZ& e, const GF2XModulus& F); inline void PowerMod(GF2X& x, const GF2X& g, long e, const GF2XModulus& F) { PowerMod(x, g, ZZ_expo(e), F); } void PowerXMod(GF2X& hh, const ZZ& e, const GF2XModulus& F); inline void PowerXMod(GF2X& x, long e, const GF2XModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline GF2X PowerMod(const GF2X& g, const ZZ& e, const GF2XModulus& F) { GF2X x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerMod(const GF2X& g, long e, const GF2XModulus& F) { GF2X x; PowerMod(x, g, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerXMod(const ZZ& e, const GF2XModulus& F) { GF2X x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X PowerXMod(long e, const GF2XModulus& F) { GF2X x; PowerXMod(x, e, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator%(const GF2X& a, const GF2XModulus& F) { GF2X x; rem(x, a, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator%=(GF2X& x, const GF2XModulus& F) { rem(x, x, F); return x; } inline GF2X operator/(const GF2X& a, const GF2XModulus& F) { GF2X x; div(x, a, F); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator/=(GF2X& x, const GF2XModulus& F) { div(x, x, F); return x; } void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); void div(GF2X& q, const GF2X& a, const GF2X& b); void div(GF2X& q, const GF2X& a, GF2 b); void div(GF2X& q, const GF2X& a, long b); void rem(GF2X& r, const GF2X& a, const GF2X& b); inline GF2X operator/(const GF2X& a, const GF2X& b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator/(const GF2X& a, GF2 b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X operator/(const GF2X& a, long b) { GF2X x; div(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator/=(GF2X& x, GF2 b) { div(x, x, b); return x; } inline GF2X& operator/=(GF2X& x, long b) { div(x, x, b); return x; } inline GF2X& operator/=(GF2X& x, const GF2X& b) { div(x, x, b); return x; } inline GF2X operator%(const GF2X& a, const GF2X& b) { GF2X x; rem(x, a, b); NTL_OPT_RETURN(GF2X, x); } inline GF2X& operator%=(GF2X& x, const GF2X& b) { rem(x, x, b); return x; } void GCD(GF2X& d, const GF2X& a, const GF2X& b); inline GF2X GCD(const GF2X& a, const GF2X& b) { GF2X x; GCD(x, a, b); NTL_OPT_RETURN(GF2X, x); } void OldGCD(GF2X& d, const GF2X& a, const GF2X& b); void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); void OldXGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); void diff(GF2X& c, const GF2X& a); inline GF2X diff(const GF2X& a) { GF2X x; diff(x, a); NTL_OPT_RETURN(GF2X, x); } void conv(GF2X& c, long a); void conv(GF2X& c, GF2 a); void conv(GF2X& x, const vec_GF2& a); inline void conv(GF2X& x, const ZZ& a) { conv(x, to_GF2(a)); } void conv(vec_GF2& x, const GF2X& a); inline GF2X to_GF2X(long a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(GF2 a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(const vec_GF2& a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline GF2X to_GF2X(const ZZ& a) { GF2X x; conv(x, a); NTL_OPT_RETURN(GF2X, x); } inline vec_GF2 to_vec_GF2(const GF2X& a) { vec_GF2 x; conv(x, a); NTL_OPT_RETURN(vec_GF2, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(GF2X& x, const GF2X& a) { x = a; } class ZZX; void conv(GF2X& x, const ZZX& a); void conv(ZZX& x, const GF2X& a); /* ------------------------------------- */ inline GF2X& GF2X::operator=(long a) { conv(*this, a); return *this; } inline GF2X& GF2X::operator=(GF2 a) { conv(*this, a); return *this; } void VectorCopy(vec_GF2& x, const GF2X& a, long n); inline vec_GF2 VectorCopy(const GF2X& a, long n) { vec_GF2 x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } void MulTrunc(GF2X& c, const GF2X& a, const GF2X& b, long n); inline GF2X MulTrunc(const GF2X& a, const GF2X& b, long n) { GF2X x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(GF2X, x); } void SqrTrunc(GF2X& c, const GF2X& a, long n); inline GF2X SqrTrunc(const GF2X& a, long n) { GF2X x; SqrTrunc(x, a, n); NTL_OPT_RETURN(GF2X, x); } long divide(GF2X& q, const GF2X& a, const GF2X& b); long divide(const GF2X& a, const GF2X& b); /*** modular composition routines and data structures ***/ struct GF2XArgument { vec_GF2X H; }; void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& A, const GF2XModulus& F); inline GF2X CompMod(const GF2X& g, const GF2XArgument& A, const GF2XModulus& F) { GF2X x; CompMod(x, g, A, F); NTL_OPT_RETURN(GF2X, x); } void build(GF2XArgument& A, const GF2X& h, const GF2XModulus& F, long m); void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F); inline GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F) { GF2X x; CompMod(x, g, h, F); NTL_OPT_RETURN(GF2X, x); } void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F); void Comp3Mod(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F); void MinPolySeq(GF2X& h, const vec_GF2& a, long m); inline GF2X MinPolySeq(const vec_GF2& a, long m) { GF2X x; MinPolySeq(x, a, m); NTL_OPT_RETURN(GF2X, x); } void ProbMinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F); inline GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void ProbMinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m); inline GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F); inline GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; MinPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void MinPolyMod(GF2X& hh, const GF2X& g, const GF2XModulus& F, long m); inline GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); inline GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F) { GF2X x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(GF2X, x); } void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); inline GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m) { GF2X x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(GF2X, x); } // undocumented stuff: void MinPolyInternal(GF2X& h, const GF2X& x, long m); void OldMinPolyInternal(GF2X& h, const GF2X& x, long m); struct GF2XTransMultiplier { GF2X f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F); void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); inline vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F) { vec_GF2 x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_GF2, x); } inline void project(ref_GF2 x, const vec_GF2& a, const GF2X& b) { x = to_GF2(InnerProduct(a.rep, b.xrep)); } inline GF2 project(const vec_GF2& a, const GF2X& b) { return to_GF2(InnerProduct(a.rep, b.xrep)); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); inline vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F) { vec_GF2 x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2, x); } void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); inline vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2X& H, const GF2XModulus& F) { vec_GF2 x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_GF2, x); } void TraceVec(vec_GF2& S, const GF2X& f); inline vec_GF2 TraceVec(const GF2X& f) { vec_GF2 x; TraceVec(x, f); NTL_OPT_RETURN(vec_GF2, x); } void TraceMod(ref_GF2 x, const GF2X& a, const GF2XModulus& F); inline GF2 TraceMod(const GF2X& a, const GF2XModulus& F) { GF2 x; TraceMod(x, a, F); return x; } void TraceMod(ref_GF2 x, const GF2X& a, const GF2X& f); inline GF2 TraceMod(const GF2X& a, const GF2X& f) { GF2 x; TraceMod(x, a, f); return x; } void GF2XFromBytes(GF2X& x, const unsigned char *p, long n); inline GF2X GF2XFromBytes(const unsigned char *p, long n) { GF2X x; GF2XFromBytes(x, p, n); NTL_OPT_RETURN(GF2X, x); } void BytesFromGF2X(unsigned char *p, const GF2X& a, long n); inline long NumBits(const GF2X& a) { return deg(a) + 1; } inline long NumBytes(const GF2X& a) { return (NumBits(a) + 7)/8; } // GF2X scratch variabes class GF2XWatcher { public: GF2X& watched; explicit GF2XWatcher(GF2X& _watched) : watched(_watched) {} ~GF2XWatcher() { watched.KillBig(); } }; #define NTL_GF2XRegister(x) NTL_TLS_LOCAL(GF2X, x); GF2XWatcher _WATCHER__ ## x(x) // RAII for HexOutput class GF2XHexOutputPush { private: long OldHexOutput; GF2XHexOutputPush(const GF2XHexOutputPush&); // disable void operator=(const GF2XHexOutputPush&); // disable public: GF2XHexOutputPush() : OldHexOutput(GF2X::HexOutput) { } ~GF2XHexOutputPush() { GF2X::HexOutput = OldHexOutput; } }; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2XFactoring.h0000644417616742025610000000326414064716022020756 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_GF2XFactoring__H #define NTL_GF2XFactoring__H #include #include NTL_OPEN_NNS long IterIrredTest(const GF2X& f); void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& ff); inline vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f) { vec_pair_GF2X_long x; SquareFreeDecomp(x, f); return x; } void DDF(vec_pair_GF2X_long& factors, const GF2X& ff, long verbose=0); inline vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0) { vec_pair_GF2X_long x; DDF(x, f, verbose); return x; } void EDF(vec_GF2X& factors, const GF2X& ff, long d, long verbose=0); inline vec_GF2X EDF(const GF2X& f, long d, long verbose=0) { vec_GF2X x; EDF(x, f, d, verbose); return x; } void SFCanZass(vec_GF2X& factors, const GF2X& ff, long verbose=0); inline vec_GF2X SFCanZass(const GF2X& f, long verbose=0) { vec_GF2X x; SFCanZass(x, f, verbose); return x; } void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); inline vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0) { vec_pair_GF2X_long x; CanZass(x, f, verbose); return x; } void mul(GF2X& f, const vec_pair_GF2X_long& v); inline GF2X mul(const vec_pair_GF2X_long& v) { GF2X x; mul(x, v); return x; } void BuildIrred(GF2X& f, long n); inline GF2X BuildIrred_GF2X(long n) { GF2X x; BuildIrred(x, n); NTL_OPT_RETURN(GF2X, x); } void BuildRandomIrred(GF2X& f, const GF2X& g); inline GF2X BuildRandomIrred(const GF2X& g) { GF2X x; BuildRandomIrred(x, g); NTL_OPT_RETURN(GF2X, x); } void BuildSparseIrred(GF2X& f, long n); inline GF2X BuildSparseIrred_GF2X(long n) { GF2X x; BuildSparseIrred(x, n); NTL_OPT_RETURN(GF2X, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/GF2XVec.h0000644417616742025610000000360714064716022017560 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_GF2XVec__H #define NTL_GF2XVec__H #include NTL_OPEN_NNS /***************************************************************** The class GF2XVec implements vectors of fixed-length GF2X's. You can allocate a vector of GF2X's of a specified length, where the maximum size of each GF2X is also specified. These parameters can be specified once, either with a constructor, or with SetSize. It is an error to try to re-size a vector, or store a GF2X that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_GF2X. *****************************************************************/ class GF2XVec { private: GF2X* v; long len; long bsize; public: GF2XVec& operator=(const GF2XVec&); GF2XVec(const GF2XVec&); long length() const { return len; } long BaseSize() const { return bsize; } void SetSize(long n, long d); void kill(); GF2XVec() : v(0), len(0), bsize(0) { } GF2XVec(long n, long d) : v(0), len(0), bsize(0) { SetSize(n, d); } ~GF2XVec() { kill(); }; GF2X* elts() { return v; } const GF2X* elts() const { return v; } GF2X& operator[](long i) { return v[i]; } const GF2X& operator[](long i) const { return v[i]; } void swap(GF2XVec& x) { _ntl_swap(v, x.v); _ntl_swap(len, x.len); _ntl_swap(bsize, x.bsize); } void move(GF2XVec& other) { GF2XVec tmp; tmp.swap(other); tmp.swap(*this); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) GF2XVec(GF2XVec&& other) noexcept : GF2XVec() { this->move(other); } GF2XVec& operator=(GF2XVec&& other) noexcept { this->move(other); return *this; } #endif }; NTL_DECLARE_RELOCATABLE((GF2XVec*)) inline void swap(GF2XVec& x, GF2XVec& y) { x.swap(y); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/HNF.h0000644417616742025610000000136514064716022017026 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_HNF__H #define NTL_HNF__H #include NTL_OPEN_NNS void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D); // The input matrix A is an n x m matrix of rank m (so n >= m), and // D is a multiple of the determinant of the lattice L spanned by // the rows of A. // W is computed as the Hermite Normal Form of A; // that is, W is the unique m x m matrix whose rows span L, such that // - W is lower triangular, // - the diagonal entries are positive, // - any entry below the diagonal is a non-negative number // strictly less than the diagonal entry in its column. // Currently, this is implemented using the algorithm of // [P. Domich, R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ctools.h0000644417616742025610000003245214064716022017717 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ctools__H #define NTL_ctools__H #include #include #include #include #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) #define NTL_GNUC_INTEL #endif #if (!defined(NTL_HAVE_LL_TYPE) && defined(NTL_WINPACK) && (defined(_MSC_VER) || defined(NTL_GNUC_INTEL))) // for the windows distribution, // we assume LL_TYPE works for MSVC++ (which is true for both x86 and ARM) // and for GNUC/Intel platforms (e.g., Code Blocks) #define NTL_HAVE_LL_TYPE #endif // Define the working C++ standard. // Both NTL_STD_CXX14 and NTL_STD_CXX11, and we take the highest one #if defined(NTL_STD_CXX14) #define NTL_CXX_STANDARD (2014) #elif defined(NTL_STD_CXX11) #define NTL_CXX_STANDARD (2011) #else #define NTL_CXX_STANDARD (1998) #endif // define some macros regarding noexcept declarations #if (NTL_CXX_STANDARD >= 2011) #define NTL_NOEXCEPT noexcept #ifdef NTL_EXCEPTIONS #define NTL_FAKE_NOEXCEPT #else #define NTL_FAKE_NOEXCEPT noexcept #endif #else #define NTL_NOEXCEPT #define NTL_FAKE_NOEXCEPT #endif /* * Resolve double-word integer type. * * Unfortunately, there is no "standard" way to do this. * On 32-bit machines, 'long long' usually works (but not * on MSVC++ or BORLAND), and on 64-bit machines, there is * no standard. However, most compilers do offer *some* * non-standard double-word type. * * Note that C99 creates a standard header , * but it is not clear how widely this is implemented, * and for example, older versions of GCC does not provide a type int128_t * in on 64-bit machines. */ #if (defined(NTL_UNSIGNED_LONG_LONG_TYPE)) #define NTL_ULL_TYPE NTL_UNSIGNED_LONG_LONG_TYPE #elif (NTL_BITS_PER_LONG == 64 && defined(__GNUC__)) #define NTL_ULL_TYPE __uint128_t #elif (NTL_BITS_PER_LONG == 32 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_ULL_TYPE unsigned __int64 #elif (NTL_BITS_PER_LONG == 64 && (defined(_MSC_VER) || defined(__BORLANDC__))) #define NTL_ULL_TYPE unsigned __int128 #endif #if (!defined(NTL_ULL_TYPE)) #define NTL_ULL_TYPE unsigned long long #endif #ifdef NTL_HAVE_LL_TYPE typedef NTL_ULL_TYPE _ntl_ulonglong; // typenames are more convenient than macros #else #undef NTL_ULL_TYPE // prevent any use of these macros class _ntl_ulonglong { private: _ntl_ulonglong() { } }; // cannot create variables of these types #endif /********************************************************/ // Define an unsigned type with at least 32 bits // there is no truly portable way to do this, yet... #if (NTL_BITS_PER_INT >= 32) typedef unsigned int _ntl_uint32; // 32-bit word #define NTL_BITS_PER_INT32 NTL_BITS_PER_INT #else // NOTE: C++ standard guarantees longs are at least 32-bits wide, // and this is also explicitly checked at builod time typedef unsigned long _ntl_uint32; // 32-bit word #define NTL_BITS_PER_INT32 NTL_BITS_PER_LONG #endif // The usual token pasting stuff... #define NTL_PASTE_TOKENS2(a,b) a ## b #define NTL_PASTE_TOKENS(a,b) NTL_PASTE_TOKENS2(a,b) #define NTL_STRINGIFY(x) NTL_STRINGIFY_AUX(x) #define NTL_STRINGIFY_AUX(x) #x #define NTL_OVFBND (1L << (NTL_BITS_PER_LONG-4)) /* * NTL_OVFBND is the general bound used throughout NTL to keep various * integer values comfortably bounded away from an integer overflow * condition. Do not change this value! */ #if ((NTL_BITS_PER_SIZE_T-1) < (NTL_BITS_PER_LONG-4)) #define NTL_OVFBND1 (1L << (NTL_BITS_PER_SIZE_T-1)) #else #define NTL_OVFBND1 NTL_OVFBND #endif /* * NTL_OVFBND1 is a smaller bound than NTL_OVF when size_t is * narrower than long. This prevents overflow on calls to malloc * and realloc. */ #define NTL_OVERFLOW(n, a, b) \ (((b) >= NTL_OVFBND) || (((long) (n)) > 0 && (((a) >= NTL_OVFBND) || \ (((long) (n)) >= (NTL_OVFBND-((long)(b))+((long)(a))-1)/((long)(a)))))) /* * NTL_OVERFLOW(n, a, b) returns 1 if n*a + b >= NTL_OVFBND, * and returns 0 otherwise. The value n is effectively treated as type long, * while the values a and b may be *any* integral type. It is assumed that * n >= 0, a > 0, and b >= 0. Care is taken to ensure that overflow does * not occur. If a and b are constants, and n has no side effects, * a good optimizing compiler will * translate this into a single test * of the form n >= c, where c is a constant. */ #define NTL_OVERFLOW1(n, a, b) \ (((b) >= NTL_OVFBND1) || (((long) (n)) > 0 && (((a) >= NTL_OVFBND1) || \ (((long) (n)) >= (NTL_OVFBND1-((long)(b))+((long)(a))-1)/((long)(a)))))) /* * NTL_OVERFLOW1 is the same as NTL_OVERFLOW, except that it uses the * bound NTL_OVFBND1 instead of NTL_OVFBND. */ #ifdef NTL_TEST_EXCEPTIONS extern unsigned long exception_counter; #define NTL_BASIC_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) malloc(((long)(n))*((long)(a)) + ((long)(b))))) #define NTL_MALLOC(n, a, b) \ (--exception_counter == 0 ? (void *) 0 : NTL_BASIC_MALLOC(n, a, b)) #else #define NTL_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) malloc(((long)(n))*((long)(a)) + ((long)(b))))) #endif /* * NTL_MALLOC(n, a, b) returns 0 if a*n + b >= NTL_OVFBND1, and otherwise * returns malloc(n*a + b). * The programmer must ensure that the name "malloc" is visible * at the point in the source code where this macro is expanded. */ #ifdef NTL_TEST_EXCEPTIONS #define NTL_BASIC_SNS_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) NTL_SNS malloc(((long)(n))*((long)(a)) + ((long)(b))))) #define NTL_SNS_MALLOC(n, a, b) \ (--exception_counter == 0 ? (void *) 0 : NTL_BASIC_SNS_MALLOC(n, a, b)) #else #define NTL_SNS_MALLOC(n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) NTL_SNS malloc(((long)(n))*((long)(a)) + ((long)(b))))) #endif /* * NTL_SNS_MALLOC is the same as NTL_MALLOC, except that the call * to malloc is prefixed by NTL_SNS. */ #define NTL_REALLOC(p, n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) realloc((p), ((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_REALLOC(n, a, b) returns 0 if a*n + b >= NTL_OVFBND1, and otherwise * returns realloc(p, n*a + b). * The programmer must ensure that the name "realloc" is visible * at the point in the source code where this macro is expanded. */ #define NTL_SNS_REALLOC(p, n, a, b) \ (NTL_OVERFLOW1(n, a, b) ? ((void *) 0) : \ ((void *) NTL_SNS realloc((p), ((long)(n))*((long)(a)) + ((long)(b))))) /* * NTL_SNS_REALLOC is the same as NTL_REALLOC, except that the call * to realloc is prefixed by NTL_SNS. */ #define NTL_MAX_ALLOC_BLOCK (40000) /* * NTL_MAX_ALLOC_BLOCK is the number of bytes that are allocated in * a single block in a number of places throughout NTL (for * vec_ZZ_p, ZZVec, vec_GF2X, and GF2XVec). */ #define NTL_ULONG_TO_LONG(a) \ ((((unsigned long) a) >> (NTL_BITS_PER_LONG-1)) ? \ (((long) (((unsigned long) a) ^ ((unsigned long) NTL_MIN_LONG))) ^ \ NTL_MIN_LONG) : \ ((long) a)) /* * This macro converts from unsigned long to signed long. It is portable * among platforms for which a long has a 2's complement representation * of the same width as an unsigned long. While it avoids assumptions * about the behavior of non-standard conversions, a good optimizing * compiler should turn it into the identity function. */ #define NTL_UINT_TO_INT(a) \ ((((unsigned int) a) >> (NTL_BITS_PER_INT-1)) ? \ (((int) (((unsigned int) a) ^ ((unsigned int) NTL_MIN_INT))) ^ \ NTL_MIN_INT) : \ ((int) a)) /* * This macro converts from unsigned int to signed int. It is portable * among platforms for which an int has a 2's complement representation * of the same width as an unsigned int. While it avoids assumptions * about the behavior of non-standard conversions, a good optimizing * compiler should turn it into the identity function. */ #ifdef NTL_THREADS #define NTL_THREAD_LOCAL thread_local #ifdef __GNUC__ #define NTL_CHEAP_THREAD_LOCAL __thread #else #define NTL_CHEAP_THREAD_LOCAL thread_local #endif #else #define NTL_THREAD_LOCAL #define NTL_CHEAP_THREAD_LOCAL #endif #define NTL_RELEASE_THRESH (128) /* * threshold for releasing scratch memory. */ double _ntl_GetWallTime(); long _ntl_IsFinite(double *p); /* This forces a double into memory, and tests if it is "normal"; that means, not NaN, not +/- infinity, not denormalized, etc. Forcing into memory is sometimes necessary on machines with "extended" double precision registers (e.g., Intel x86s) to force the standard IEEE format. */ void _ntl_ForceToMem(double *p); /* This is do-nothing routine that has the effect of forcing a double into memory (see comment above). */ double _ntl_ldexp(double x, long e); #define NTL_DEFINE_SWAP(T)\ inline void _ntl_swap(T& a, T& b)\ {\ T t = a; a = b; b = t;\ } NTL_DEFINE_SWAP(long) NTL_DEFINE_SWAP(int) NTL_DEFINE_SWAP(short) NTL_DEFINE_SWAP(char) NTL_DEFINE_SWAP(unsigned long) NTL_DEFINE_SWAP(unsigned int) NTL_DEFINE_SWAP(unsigned short) NTL_DEFINE_SWAP(unsigned char) NTL_DEFINE_SWAP(double) NTL_DEFINE_SWAP(float) template void _ntl_swap(T*& a, T*& b) { T* t = a; a = b; b = t; } /* These are convenience routines. I don't want it to overload the std library's swap function, nor do I want to rely on the latter, as the C++ standard is kind of broken on the issue of where swap is defined. And I also only want it defined for built-in types. */ // The following do for "move" what the above does for swap #define NTL_DEFINE_SCALAR_MOVE(T)\ inline T _ntl_scalar_move(T& a)\ {\ T t = a; a = 0; return t;\ } NTL_DEFINE_SCALAR_MOVE(long) NTL_DEFINE_SCALAR_MOVE(int) NTL_DEFINE_SCALAR_MOVE(short) NTL_DEFINE_SCALAR_MOVE(char) NTL_DEFINE_SCALAR_MOVE(unsigned long) NTL_DEFINE_SCALAR_MOVE(unsigned int) NTL_DEFINE_SCALAR_MOVE(unsigned short) NTL_DEFINE_SCALAR_MOVE(unsigned char) NTL_DEFINE_SCALAR_MOVE(double) NTL_DEFINE_SCALAR_MOVE(float) template T* _ntl_scalar_move(T*& a) { T *t = a; a = 0; return t; } // The following routine increments a pointer so that // it is properly aligned. // It is assumed that align > 0. // If align is a constant power of 2, it compiles // into a small handful of simple instructions. #if (NTL_BIG_POINTERS) #define NTL_UPTRINT_T unsigned long long // DIRT: this should really be std::uintptr_t, defined // in ; however, that header is not widely available, // and even if it were, std::uintptr_t is not guaranteed // to be defined. Of course, unsigned long long may not // be defined in pre-C++11. #else #define NTL_UPTRINT_T unsigned long #endif #ifdef NTL_HAVE_ALIGNED_ARRAY inline char *_ntl_make_aligned(char *p, long align) { unsigned long r = (unsigned long) (((NTL_UPTRINT_T) (p)) % ((NTL_UPTRINT_T) (align))); return p + ((((unsigned long) (align)) - r) % ((unsigned long) (align))); } #else inline char *_ntl_make_aligned(char *p, long align) { return p; } #endif // The following is for aligning small local arrays // Equivalent to type x[n], but aligns to align bytes // Only works for POD types // NOTE: the gcc aligned attribute might work, but there is // some chatter on the web that this was (at some point) buggy. // Not clear what the current status is. // Anyway, this is only intended for use with gcc on intel // machines, so it should be OK. #define NTL_ALIGNED_LOCAL_ARRAY(align, x, type, n) \ char x##__ntl_hidden_variable_storage[n*sizeof(type)+align]; \ type *x = (type *) _ntl_make_aligned(&x##__ntl_hidden_variable_storage[0], align); #define NTL_AVX_BYTE_ALIGN (32) #define NTL_AVX_DBL_ALIGN (NTL_AVX_BYTE_ALIGN/long(sizeof(double))) #define NTL_AVX_LOCAL_ARRAY(x, type, n) NTL_ALIGNED_LOCAL_ARRAY(NTL_AVX_BYTE_ALIGN, x, type, n) #define NTL_AVX512_BYTE_ALIGN (64) #define NTL_AVX512_LOCAL_ARRAY(x, type, n) NTL_ALIGNED_LOCAL_ARRAY(NTL_AVX512_BYTE_ALIGN, x, type, n) #define NTL_DEFAULT_ALIGN (64) // this should be big enough to satisfy any SIMD instructions, // and it should also be as big as a cache line #ifdef NTL_HAVE_BUILTIN_CLZL inline long _ntl_count_bits(unsigned long x) { return x ? (NTL_BITS_PER_LONG - __builtin_clzl(x)) : 0; } #else inline long _ntl_count_bits(unsigned long x) { if (!x) return 0; long res = NTL_BITS_PER_LONG; while (x < (1UL << (NTL_BITS_PER_LONG-1))) { x <<= 1; res--; } return res; } #endif #if (!defined(NTL_CLEAN_INT) && NTL_ARITH_RIGHT_SHIFT && (NTL_BITS_PER_LONG == (1 << (NTL_NUMBITS_BPL-1)))) inline void _ntl_bpl_divrem(long a, long& q, long& r) { q = a >> (NTL_NUMBITS_BPL-1); r = a & (NTL_BITS_PER_LONG-1); } #else inline void _ntl_bpl_divrem(long a, long& q, long& r) { q = a / NTL_BITS_PER_LONG; r = a % NTL_BITS_PER_LONG; if (r < 0) { q--; r += NTL_BITS_PER_LONG; } } #endif inline void _ntl_bpl_divrem(unsigned long a, long& q, long& r) { q = a / NTL_BITS_PER_LONG; r = a % NTL_BITS_PER_LONG; } // vectors are grown by a factor of 1.5 inline long _ntl_vec_grow(long n) { return n + n/2; } template struct _ntl_is_char_pointer { enum {value = false}; }; template <> struct _ntl_is_char_pointer { enum {value = true}; }; template <> struct _ntl_is_char_pointer { enum {value = true}; }; template struct _ntl_enable_if {}; template struct _ntl_enable_if { typedef T type; }; #endif ntl-11.5.1/include/NTL/LLL.h0000644417616742025610000001326114064716022017034 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_LLL__H #define NTL_LLL__H #include #include NTL_OPEN_NNS long LLL(ZZ& det, mat_ZZ& B, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, long a, long b, long verbose = 0); long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose=0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose=0); long image(ZZ& det, mat_ZZ& B, long verbose = 0); long image(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0); typedef long (*LLLCheckFct)(const vec_ZZ&); extern NTL_CHEAP_THREAD_LOCAL double LLLStatusInterval; extern NTL_CHEAP_THREAD_LOCAL char *LLLDumpFile; // classical Gramm-Schmidt versions long LLL_FP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_FP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0) ; long BKZ_FP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_XD(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_XD(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_XD(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_QP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP1(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_QP1(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long LLL_RR(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long BKZ_RR(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long BKZ_RR(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); // Givens rotations versions long G_LLL_FP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_FP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_FP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0) ; long G_BKZ_FP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_XD(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_XD(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_XD(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_XD(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_QP(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_QP(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP1(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_QP1(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_RR(mat_ZZ& B, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_LLL_RR(mat_ZZ& B, mat_ZZ& U, double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_RR(mat_ZZ& BB, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); long G_BKZ_RR(mat_ZZ& BB, mat_ZZ& U, double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c); void NearVector(vec_ZZ& ww, const mat_ZZ& BB, const vec_ZZ& a); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/RR.h0000644417616742025610000003751714064716022016746 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_RR__H #define NTL_RR__H #include #include #include NTL_OPEN_NNS class RR { public: ZZ x; long e; RR() { e = 0; } explicit RR(double a) : e(0) { *this = a; } inline RR(INIT_VAL_TYPE, const ZZ& a); inline RR(INIT_VAL_TYPE, int a); inline RR(INIT_VAL_TYPE, long a); inline RR(INIT_VAL_TYPE, unsigned int a); inline RR(INIT_VAL_TYPE, unsigned long a); inline RR(INIT_VAL_TYPE, float a); inline RR(INIT_VAL_TYPE, double a); inline RR(INIT_VAL_TYPE, const xdouble& a); inline RR(INIT_VAL_TYPE, const quad_float& a); inline RR(INIT_VAL_TYPE, const char *a); // read from string inline RR(INIT_VAL_TYPE, const RR& a); inline RR& operator=(double a); RR(RR& z, INIT_TRANS_TYPE) : x(z.x, INIT_TRANS), e(z.e) { } void swap(RR& z) { x.swap(z.x); _ntl_swap(e, z.e); } const ZZ& mantissa() const { return x; } long exponent() const { return e; } static NTL_CHEAP_THREAD_LOCAL long prec; static void SetPrecision(long p); static long precision() { return prec; } static NTL_CHEAP_THREAD_LOCAL long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } #ifdef NTL_TRANSITION private: RR& operator=(const RR&); RR(const RR&); #endif }; NTL_DECLARE_RELOCATABLE((RR*)) inline void swap(RR& a, RR& b) { a.swap(b); } class RRPush { private: long old_p; RRPush(const RRPush&); // disable void operator=(const RRPush&); // disable public: RRPush() : old_p(RR::prec) { } ~RRPush() { RR::prec = old_p; } }; // RAII for saving/restoring output precision // FIXME: document. class RROutputPush { private: long old_p; RROutputPush(const RROutputPush&); // disable void operator=(const RROutputPush&); // disable public: RROutputPush() : old_p(RR::oprec) { } ~RROutputPush() { RR::oprec = old_p; } }; long IsZero(const RR& a); long IsOne(const RR& a); long sign(const RR& a); void clear(RR& z); void set(RR& z); void add(RR& z, const RR& a, const RR& b); void add(RR& z, const RR& a, double b); inline void add(RR& z, double a, const RR& b) { add(z, b, a); } void sub(RR& z, const RR& a, const RR& b); void sub(RR& z, const RR& a, double b); void sub(RR& z, double a, const RR& b); void negate(RR& z, const RR& a); void abs(RR& z, const RR& a); inline RR abs(const RR& a) { RR z; abs(z, a); NTL_OPT_RETURN(RR, z); } inline RR fabs(const RR& a) { RR z; abs(z, a); NTL_OPT_RETURN(RR, z); } void mul(RR& z, const RR& a, const RR& b); void mul(RR& z, const RR& a, double b); inline void mul(RR& z, double a, const RR& b) { mul(z, b, a); } void sqr(RR& z, const RR& a); inline RR sqr(const RR& a) { RR z; sqr(z, a); NTL_OPT_RETURN(RR, z); } void div(RR& z, const RR& a, const RR& b); void div(RR& z, const RR& a, double b); void div(RR& z, double a, const RR& b); void inv(RR& z, const RR& a); inline RR inv(const RR& a) { RR z; inv(z, a); NTL_OPT_RETURN(RR, z); } // operator notation: inline RR operator+(const RR& a, const RR& b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator+(const RR& a, double b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator+(double a, const RR& b) { RR x; add(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator+=(RR& x, const RR& b) { add(x, x, b); return x; } inline RR& operator+=(RR& x, double b) { add(x, x, b); return x; } inline RR operator-(const RR& a, const RR& b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator-(const RR& a, double b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator-(double a, const RR& b) { RR x; sub(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator-=(RR& x, const RR& b) { sub(x, x, b); return x; } inline RR& operator-=(RR& x, double b) { sub(x, x, b); return x; } inline RR operator*(const RR& a, const RR& b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator*(const RR& a, double b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator*(double a, const RR& b) { RR x; mul(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator*=(RR& x, const RR& b) { mul(x, x, b); return x; } inline RR& operator*=(RR& x, double b) { mul(x, x, b); return x; } inline RR operator/(const RR& a, const RR& b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator/(const RR& a, double b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR operator/(double a, const RR& b) { RR x; div(x, a, b); NTL_OPT_RETURN(RR, x); } inline RR& operator/=(RR& x, const RR& b) { div(x, x, b); return x; } inline RR& operator/=(RR& x, double b) { div(x, x, b); return x; } inline RR operator-(const RR& a) { RR x; negate(x, a); NTL_OPT_RETURN(RR, x); } inline RR& operator++(RR& x) { add(x, x, 1); return x; } inline void operator++(RR& x, int) { add(x, x, 1); } inline RR& operator--(RR& x) { sub(x, x, 1); return x; } inline void operator--(RR& x, int) { sub(x, x, 1); } long compare(const RR& a, const RR& b); long compare(const RR& a, double b); inline long compare(double a, const RR& b) { return -compare(b, a); } long operator==(const RR& a, const RR& b); inline long operator!=(const RR& a, const RR& b) { return !(a == b); } inline long operator<=(const RR& a, const RR& b) { return compare(a, b) <= 0; } inline long operator>=(const RR& a, const RR& b) { return compare(a, b) >= 0; } inline long operator <(const RR& a, const RR& b) { return compare(a, b) < 0; } inline long operator >(const RR& a, const RR& b) { return compare(a, b) > 0; } long operator==(const RR& a, double b); inline long operator!=(const RR& a, double b) { return !(a == b); } inline long operator<=(const RR& a, double b) { return compare(a, b) <= 0; } inline long operator>=(const RR& a, double b) { return compare(a, b) >= 0; } inline long operator <(const RR& a, double b) { return compare(a, b) < 0; } inline long operator >(const RR& a, double b) { return compare(a, b) > 0; } inline long operator==(double a, const RR& b) { return (b == a); } inline long operator!=(double a, const RR& b) { return !(a == b); } inline long operator<=(double a, const RR& b) { return compare(a, b) <= 0; } inline long operator>=(double a, const RR& b) { return compare(a, b) >= 0; } inline long operator <(double a, const RR& b) { return compare(a, b) < 0; } inline long operator >(double a, const RR& b) { return compare(a, b) > 0; } void ceil(RR& z, const RR& a); inline RR ceil(const RR& a) { RR z; ceil(z, a); NTL_OPT_RETURN(RR, z); } void floor(RR& z, const RR& a); inline RR floor(const RR& a) { RR z; floor(z, a); NTL_OPT_RETURN(RR, z); } void trunc(RR& z, const RR& a); inline RR trunc(const RR& a) { RR z; trunc(z, a); NTL_OPT_RETURN(RR, z); } void round(RR& z, const RR& a); inline RR round(const RR& a) { RR z; round(z, a); NTL_OPT_RETURN(RR, z); } void RoundToPrecision(RR& z, const RR& a, long p); inline RR RoundToPrecision(const RR& a, long p) { RR z; RoundToPrecision(z, a, p); NTL_OPT_RETURN(RR, z); } // routines with a precision parameter void ConvPrec(RR& z, const RR& a, long p); inline RR ConvPrec(const RR& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void AddPrec(RR& z, const RR& a, const RR& b, long p); inline RR AddPrec(const RR& a, const RR& b, long p) { RR z; AddPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void SubPrec(RR& z, const RR& a, const RR& b, long p); inline RR SubPrec(const RR& a, const RR& b, long p) { RR z; SubPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void NegatePrec(RR& z, const RR& a, long p); inline RR NegatePrec(const RR& a, long p) { RR z; NegatePrec(z, a, p); NTL_OPT_RETURN(RR, z); } void AbsPrec(RR& z, const RR& a, long p); inline RR AbsPrec(const RR& a, long p) { RR z; AbsPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void MulPrec(RR& z, const RR& a, const RR& b, long p); inline RR MulPrec(const RR& a, const RR& b, long p) { RR z; MulPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void SqrPrec(RR& z, const RR& a, long p); inline RR SqrPrec(const RR& a, long p) { RR z; SqrPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void DivPrec(RR& z, const RR& a, const RR& b, long p); inline RR DivPrec(const RR& a, const RR& b, long p) { RR z; DivPrec(z, a, b, p); NTL_OPT_RETURN(RR, z); } void InvPrec(RR& z, const RR& a, long p); inline RR InvPrec(const RR& a, long p) { RR z; InvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void SqrRootPrec(RR& z, const RR& a, long p); inline RR SqrRootPrec(const RR& a, long p) { RR z; SqrRootPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void TruncPrec(RR& z, const RR& a, long p); inline RR TruncPrec(const RR& a, long p) { RR z; TruncPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void FloorPrec(RR& z, const RR& a, long p); inline RR FloorPrec(const RR& a, long p) { RR z; FloorPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void CeilPrec(RR& z, const RR& a, long p); inline RR CeilPrec(const RR& a, long p) { RR z; CeilPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void RoundPrec(RR& z, const RR& a, long p); inline RR RoundPrec(const RR& a, long p) { RR z; RoundPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const ZZ& a, long p); inline RR ConvPrec(const ZZ& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, long a, long p); inline RR ConvPrec(long a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } inline void ConvPrec(RR& z, int a, long p) { ConvPrec(z, long(a), p); } inline RR ConvPrec(int a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, unsigned long a, long p); inline RR ConvPrec(unsigned long a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } inline void ConvPrec(RR& z, unsigned int a, long p) { ConvPrec(z, (unsigned long)(a), p); } inline RR ConvPrec(unsigned int a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, double a, long p); inline RR ConvPrec(double a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const xdouble& a, long p); inline RR ConvPrec(const xdouble& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const quad_float& a, long p); inline RR ConvPrec(const quad_float& a, long p) { RR z; ConvPrec(z, a, p); NTL_OPT_RETURN(RR, z); } void ConvPrec(RR& z, const char *s, long p); inline RR ConvPrec(const char *s, long p) { RR z; ConvPrec(z, s, p); NTL_OPT_RETURN(RR, z); } NTL_SNS istream& InputPrec(RR& z, NTL_SNS istream& s, long p); inline RR InputPrec(NTL_SNS istream& s, long p) { RR z; NTL_INPUT_CHECK_ERR(InputPrec(z, s, p)); NTL_OPT_RETURN(RR, z); } void MakeRRPrec(RR& z, const ZZ& a, long e, long p); inline RR MakeRRPrec(const ZZ& a, long e, long p) { RR z; MakeRRPrec(z, a, e, p); NTL_OPT_RETURN(RR, z); } void conv(RR& z, const ZZ& a); void conv(RR& z, long a); inline void conv(RR& z, int a) { conv(z, long(a)); } void conv(RR& z, unsigned long a); inline void conv(RR& z, unsigned int a) { conv(z, (unsigned long)(a)); } void conv(RR& z, double a); inline void conv(RR& z, float a) { conv(z, double(a)); } void conv(RR& z, const xdouble& a); void conv(RR& z, const quad_float& a); void conv(RR& z, const RR& a); inline RR::RR(INIT_VAL_TYPE, int a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, long a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, unsigned int a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, unsigned long a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, float a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, double a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const RR& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const ZZ& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const xdouble& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const quad_float& a) { e = 0; conv(*this, a); } inline RR::RR(INIT_VAL_TYPE, const char *a) { e = 0; conv(*this, a); } inline RR to_RR(int a) { return RR(INIT_VAL, a); } inline RR to_RR(long a) { return RR(INIT_VAL, a); } inline RR to_RR(unsigned int a) { return RR(INIT_VAL, a); } inline RR to_RR(unsigned long a) { return RR(INIT_VAL, a); } inline RR to_RR(float a) { return RR(INIT_VAL, a); } inline RR to_RR(double a) { return RR(INIT_VAL, a); } inline RR to_RR(const ZZ& a) { return RR(INIT_VAL, a); } inline RR to_RR(const RR& a) { return RR(INIT_VAL, a); } inline RR to_RR(const xdouble& a) { return RR(INIT_VAL, a); } inline RR to_RR(const quad_float& a) { return RR(INIT_VAL, a); } inline RR to_RR(const char *a) { return RR(INIT_VAL, a); } inline RR& RR::operator=(double a) { conv(*this, a); return *this; } void conv(ZZ& z, const RR& a); void conv(long& z, const RR& a); void conv(double& z, const RR& a); void conv(xdouble& z, const RR& a); void conv(quad_float& z, const RR& a); inline void conv(int& z, const RR& a) { long t; conv(t, a); z = int(t); } inline void conv(float& z, const RR& a) { double t; conv(t, a); z = float(t); } inline int to_int(const RR& a) { int z; conv(z, a); return z; } inline long to_long(const RR& a) { long z; conv(z, a); return z; } inline float to_float(const RR& a) { float z; conv(z, a); return z; } inline double to_double(const RR& a) { double z; conv(z, a); return z; } inline xdouble to_xdouble(const RR& a) { xdouble z; conv(z, a); return z; } inline quad_float to_quad_float(const RR& a) { quad_float z; conv(z, a); return z; } inline ZZ to_ZZ(const RR& a) { ZZ z; conv(z, a); NTL_OPT_RETURN(ZZ, z); } void CeilToZZ(ZZ& z, const RR& a); inline ZZ CeilToZZ(const RR& a) { ZZ z; CeilToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } void TruncToZZ(ZZ& z, const RR& a); inline ZZ TruncToZZ(const RR& a) { ZZ z; TruncToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } void RoundToZZ(ZZ& z, const RR& a); inline ZZ RoundToZZ(const RR& a) { ZZ z; RoundToZZ(z, a); NTL_OPT_RETURN(ZZ, z); } inline void FloorToZZ(ZZ& z, const RR& a) { conv(z, a); } inline ZZ FloorToZZ(const RR& a) { ZZ z; conv(z, a); NTL_OPT_RETURN(ZZ, z); } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const RR& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const RR& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ void MakeRR(RR& z, const ZZ& a, long e); inline RR MakeRR(const ZZ& a, long e) { RR z; MakeRR(z, a, e); NTL_OPT_RETURN(RR, z); } void random(RR& z); inline RR random_RR() { RR z; random(z); NTL_OPT_RETURN(RR, z); } void power(RR& z, const RR& a, long e); inline RR power(const RR& a, long e) { RR z; power(z, a, e); NTL_OPT_RETURN(RR, z); } void power2(RR& z, long e); inline RR power2_RR(long e) { RR z; power2(z, e); NTL_OPT_RETURN(RR, z); } NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const RR& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, RR& x); void SqrRoot(RR& x, const RR& a); inline RR SqrRoot(const RR& a) { RR z; SqrRoot(z, a); NTL_OPT_RETURN(RR, z); } inline RR sqrt(const RR& a) { RR z; SqrRoot(z, a); NTL_OPT_RETURN(RR, z); } void exp(RR& res, const RR& x); inline RR exp(const RR& a) { RR z; exp(z, a); NTL_OPT_RETURN(RR, z); } void log(RR& res, const RR& x); inline RR log(const RR& a) { RR z; log(z, a); NTL_OPT_RETURN(RR, z); } void log10(RR& res, const RR& x); inline RR log10(const RR& a) { RR z; log10(z, a); NTL_OPT_RETURN(RR, z); } void expm1(RR& res, const RR& x); inline RR expm1(const RR& a) { RR z; expm1(z, a); NTL_OPT_RETURN(RR, z); } void log1p(RR& res, const RR& x); inline RR log1p(const RR& a) { RR z; log1p(z, a); NTL_OPT_RETURN(RR, z); } void pow(RR& res, const RR& x, const RR& y); inline RR pow(const RR& x, const RR& y) { RR z; pow(z, x, y); NTL_OPT_RETURN(RR, z); } void ComputePi(RR& res); inline RR ComputePi_RR() { RR z; ComputePi(z); NTL_OPT_RETURN(RR, z); } void sin(RR& res, const RR& x); inline RR sin(const RR& a) { RR z; sin(z, a); NTL_OPT_RETURN(RR, z); } void cos(RR& res, const RR& x); inline RR cos(const RR& a) { RR z; cos(z, a); NTL_OPT_RETURN(RR, z); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/WordVector.h0000644417616742025610000000770114064716022020511 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_WordVector__H #define NTL_WordVector__H /************************************************************** A WordVector is functionally similar to a generic NTL vector of _ntl_ulong. Be careful! the MaxLength() function does not return the max length ever set, but rather the max space allocated, which *may* be more. The FixLength() facility is not available. The reason for special-casing is efficiency (of course). **************************************************************/ #include #include NTL_OPEN_NNS #ifndef NTL_RANGE_CHECK #define NTL_WV_RANGE_CHECK_CODE #else #define NTL_WV_RANGE_CHECK_CODE if (i < 0 || !rep || i >= long(rep[-1])) LogicError("index out of range in WordVector"); #endif // vectors are allocated in chunks of this size #ifndef NTL_WordVectorMinAlloc #define NTL_WordVectorMinAlloc (4) #endif // controls initialization during input #ifndef NTL_WordVectorInputBlock #define NTL_WordVectorInputBlock 50 #endif class WordVector { public: _ntl_ulong *rep; WordVector(WordVector& x, INIT_TRANS_TYPE) { rep = x.rep; x.rep = 0; } WordVector() : rep(0) { } WordVector(INIT_SIZE_TYPE, long n) : rep(0) { DoSetLength(n); } WordVector(const WordVector& a) : rep(0) { *this = a; } WordVector& operator=(const WordVector& a); bool pinned() const { return rep && (rep[-2] & 1); } // assumes *this and other are not pinned void unpinned_swap(WordVector& other) { _ntl_swap(this->rep, other.rep); } // assumes *this and other are not pinned void unpinned_move(WordVector& other) { WordVector tmp; tmp.unpinned_swap(other); tmp.unpinned_swap(*this); } ~WordVector(); void kill(); void KillBig() { if (MaxLength() > NTL_RELEASE_THRESH) kill(); } // this conditinally kills the vector, if its size is excessive void DoSetLength(long n); void SetLength(long n) { _ntl_ulong *x = rep; if (x && long(x[-2] >> 1) >= n && n >= 0) x[-1] = n; else DoSetLength(n); } void ZeroLength() { if (rep) rep[-1] = 0; } void SetMaxLength(long n); void QuickSetLength(long n) { rep[-1] = _ntl_ulong(n); } long length() const { return (!rep) ? 0 : long(rep[-1]); } long MaxLength() const { return (!rep) ? 0 : long(rep[-2] >> 1); } _ntl_ulong& operator[](long i) { NTL_WV_RANGE_CHECK_CODE return rep[i]; } const _ntl_ulong& operator[](long i) const { NTL_WV_RANGE_CHECK_CODE return rep[i]; } _ntl_ulong& operator()(long i) { return (*this)[i-1]; } const _ntl_ulong& operator()(long i) const { return (*this)[i-1]; } const _ntl_ulong* elts() const { return rep; } _ntl_ulong* elts() { return rep; } void swap(WordVector& y); void append(_ntl_ulong a); void append(const WordVector& w); }; class WordVectorWatcher { public: WordVector& watched; explicit WordVectorWatcher(WordVector& _watched) : watched(_watched) {} ~WordVectorWatcher() { watched.KillBig(); } }; inline void swap(WordVector& x, WordVector& y) { x.swap(y); } inline void append(WordVector& v, _ntl_ulong a) { v.append(a); } inline void append(WordVector& v, const WordVector& w) { v.append(w); } NTL_SNS istream& operator>>(NTL_SNS istream&, WordVector&); NTL_SNS ostream& operator<<(NTL_SNS ostream&, const WordVector&); long operator==(const WordVector& a, const WordVector& b); long operator!=(const WordVector& a, const WordVector& b); long InnerProduct(const WordVector& a, const WordVector& b); void ShiftAdd(_ntl_ulong *cp, const _ntl_ulong* ap, long sa, long n); // cp = cp + (a << n) long WV_BlockConstructAlloc(WordVector& x, long d, long n); void WV_BlockConstructSet(WordVector& x, WordVector& y, long i); long WV_BlockDestroy(WordVector& x); long WV_storage(long d); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ.h0000644417616742025610000012245414064716022016761 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ__H #define NTL_ZZ__H /******************************************************** LIP INTERFACE The class ZZ implements signed, arbitrary length integers. **********************************************************/ #include #include #include #include #include NTL_OPEN_NNS class ZZ_p; // forward declaration class ZZX; class ZZ { public: typedef ZZ_p residue_type; typedef ZZX poly_type; class Deleter { public: static void apply(_ntl_gbigint p) { _ntl_gfree(p); } }; WrappedPtr<_ntl_gbigint_body, Deleter> rep; // This is currently public for "emergency" situations // May be private in future versions. ZZ() { } explicit ZZ(long a) { *this = a; } ZZ(INIT_SIZE_TYPE, long k) // initial value is 0, but space is pre-allocated so that numbers // x with x.size() <= k can be stored without re-allocation. // Call with ZZ(INIT_SIZE, k). // The purpose for the INIT_SIZE argument is to prevent automatic // type conversion from long to ZZ, which would be tempting, but wrong. { _ntl_gsetlength(&rep, k); } ZZ(const ZZ& a) // initial value is a. { _ntl_gcopy(a.rep, &rep); } ZZ(INIT_VAL_TYPE, long a) { _ntl_gintoz(a, &rep); } ZZ(INIT_VAL_TYPE, int a) { _ntl_gintoz(a, &rep); } ZZ(INIT_VAL_TYPE, unsigned long a) { _ntl_guintoz(a, &rep); } ZZ(INIT_VAL_TYPE, unsigned int a) { _ntl_guintoz((unsigned long) a, &rep); } inline ZZ(INIT_VAL_TYPE, const char *); inline ZZ(INIT_VAL_TYPE, float); inline ZZ(INIT_VAL_TYPE, double); ZZ& operator=(const ZZ& a) { _ntl_gcopy(a.rep, &rep); return *this; } ZZ& operator=(long a) { _ntl_gintoz(a, &rep); return *this; } void kill() // force the space held by this ZZ to be released. // The value then becomes 0. { rep.kill(); } void swap(ZZ& x) { _ntl_gswap(&rep, &x.rep); } bool pinned() const { return _ntl_PINNED(rep); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) ZZ(ZZ&& a) NTL_FAKE_NOEXCEPT { *this = std::move(a); } ZZ& operator=(ZZ&& a) NTL_FAKE_NOEXCEPT { if (pinned() || a.pinned()) { _ntl_gcopy(a.rep, &rep); } else { rep.move(a.rep); } return *this; } #endif void SetSize(long k) // pre-allocates space for k-digit numbers (base 2^NTL_ZZ_NBITS); // does not change the value. { _ntl_gsetlength(&rep, k); } long size() const // returns the number of (NTL_ZZ_NBIT-bit) digits of |a|; the size of 0 is 0. { return _ntl_gsize(rep); } long null() const // test of rep is null { return !rep; } long MaxAlloc() const // returns max allocation request, possibly rounded up a bit... { return _ntl_gmaxalloc(rep); } long SinglePrecision() const { return _ntl_gsptest(rep); } // tests if less than NTL_SP_BOUND in absolute value long WideSinglePrecision() const { return _ntl_gwsptest(rep); } // tests if less than NTL_WSP_BOUND in absolute value static const ZZ& zero(); ZZ(ZZ& x, INIT_TRANS_TYPE) { rep.swap(x.rep); } // used to cheaply hand off memory management of return value, // without copying, assuming compiler implements the // "return value optimization". This is probably obsolete by // now, as modern compilers can and should optimize // the copy constructor in the situations where this is used. // This should only be used for simple, local variables // that are not be subject to special memory management. // mainly for internal consumption by ZZWatcher void KillBig() { if (MaxAlloc() > NTL_RELEASE_THRESH) kill(); } long validate() { return _ntl_gvalidate(rep); } }; NTL_DECLARE_RELOCATABLE((ZZ*)) class ZZWatcher { public: ZZ& watched; explicit ZZWatcher(ZZ& _watched) : watched(_watched) {} ~ZZWatcher() { watched.KillBig(); } }; #define NTL_ZZRegister(x) NTL_TLS_LOCAL(ZZ, x); ZZWatcher _WATCHER__ ## x(x) const ZZ& ZZ_expo(long e); inline void clear(ZZ& x) // x = 0 { _ntl_gzero(&x.rep); } inline void set(ZZ& x) // x = 1 { _ntl_gone(&x.rep); } inline void swap(ZZ& x, ZZ& y) // swap the values of x and y (swaps pointers only) { x.swap(y); } inline double log(const ZZ& a) { return _ntl_glog(a.rep); } /********************************************************** Conversion routines. ***********************************************************/ inline void conv(ZZ& x, const ZZ& a) { x = a; } inline ZZ to_ZZ(const ZZ& a) { return a; } inline void conv(ZZ& x, long a) { _ntl_gintoz(a, &x.rep); } inline ZZ to_ZZ(long a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, int a) { _ntl_gintoz(long(a), &x.rep); } inline ZZ to_ZZ(int a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, unsigned long a) { _ntl_guintoz(a, &x.rep); } inline ZZ to_ZZ(unsigned long a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, unsigned int a) { _ntl_guintoz((unsigned long)(a), &x.rep); } inline ZZ to_ZZ(unsigned int a) { return ZZ(INIT_VAL, a); } inline ZZ::ZZ(INIT_VAL_TYPE, const char *s) { conv(*this, s); } inline ZZ to_ZZ(const char *s) { return ZZ(INIT_VAL, s); } inline void conv(ZZ& x, double a) { _ntl_gdoubtoz(a, &x.rep); } inline ZZ::ZZ(INIT_VAL_TYPE, double a) { conv(*this, a); } inline ZZ to_ZZ(double a) { return ZZ(INIT_VAL, a); } inline void conv(ZZ& x, float a) { _ntl_gdoubtoz(double(a), &x.rep); } inline ZZ::ZZ(INIT_VAL_TYPE, float a) { conv(*this, a); } inline ZZ to_ZZ(float a) { return ZZ(INIT_VAL, a); } inline void conv(long& x, const ZZ& a) { x = _ntl_gtoint(a.rep); } inline long to_long(const ZZ& a) { return _ntl_gtoint(a.rep); } inline void conv(int& x, const ZZ& a) { unsigned int res = (unsigned int) _ntl_gtouint(a.rep); x = NTL_UINT_TO_INT(res); } inline int to_int(const ZZ& a) { unsigned int res = (unsigned int) _ntl_gtouint(a.rep); return NTL_UINT_TO_INT(res); } inline void conv(unsigned long& x, const ZZ& a) { x = _ntl_gtouint(a.rep); } inline unsigned long to_ulong(const ZZ& a) { return _ntl_gtouint(a.rep); } inline void conv(unsigned int& x, const ZZ& a) { x = (unsigned int)(_ntl_gtouint(a.rep)); } inline unsigned int to_uint(const ZZ& a) { return (unsigned int)(_ntl_gtouint(a.rep)); } inline void conv(double& x, const ZZ& a) { x = _ntl_gdoub(a.rep); } inline double to_double(const ZZ& a) { return _ntl_gdoub(a.rep); } inline void conv(float& x, const ZZ& a) { x = float(_ntl_gdoub(a.rep)); } inline float to_float(const ZZ& a) { return float(_ntl_gdoub(a.rep)); } inline void ZZFromBytes(ZZ& x, const unsigned char *p, long n) { _ntl_gfrombytes(&x.rep, p, n); } inline ZZ ZZFromBytes(const unsigned char *p, long n) { ZZ x; ZZFromBytes(x, p, n); NTL_OPT_RETURN(ZZ, x); } inline void BytesFromZZ(unsigned char *p, const ZZ& a, long n) { _ntl_gbytesfromz(p, a.rep, n); } // ****** comparisons inline long sign(const ZZ& a) // returns the sign of a (-1, 0, or 1). { return _ntl_gsign(a.rep); } inline long compare(const ZZ& a, const ZZ& b) // returns the sign of a-b (-1, 0, or 1). { return _ntl_gcompare(a.rep, b.rep); } inline long IsZero(const ZZ& a) // zero test { return _ntl_giszero(a.rep); } inline long IsOne(const ZZ& a) { return _ntl_gisone(a.rep); } // test for 1 /* the usual comparison operators */ inline long operator==(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) == 0; } inline long operator!=(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) != 0; } inline long operator<(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) < 0; } inline long operator>(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) > 0; } inline long operator<=(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) <= 0; } inline long operator>=(const ZZ& a, const ZZ& b) { return _ntl_gcompare(a.rep, b.rep) >= 0; } /* single-precision versions of the above */ inline long compare(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b); } inline long compare(long a, const ZZ& b) { return -_ntl_gscompare(b.rep, a); } inline long operator==(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) == 0; } inline long operator!=(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) != 0; } inline long operator<(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) < 0; } inline long operator>(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) > 0; } inline long operator<=(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) <= 0; } inline long operator>=(const ZZ& a, long b) { return _ntl_gscompare(a.rep, b) >= 0; } inline long operator==(long a, const ZZ& b) { return b == a; } inline long operator!=(long a, const ZZ& b) { return b != a; } inline long operator<(long a, const ZZ& b) { return b > a; } inline long operator>(long a, const ZZ& b) { return b < a; } inline long operator<=(long a, const ZZ& b) { return b >= a; } inline long operator>=(long a, const ZZ& b) { return b <= a; } /************************************************** Addition **************************************************/ inline void add(ZZ& x, const ZZ& a, const ZZ& b) // x = a + b { _ntl_gadd(a.rep, b.rep, &x.rep); } inline void sub(ZZ& x, const ZZ& a, const ZZ& b) // x = a - b { _ntl_gsub(a.rep, b.rep, &x.rep); } inline void SubPos(ZZ& x, const ZZ& a, const ZZ& b) // x = a - b; assumes a >= b >= 0. { _ntl_gsubpos(a.rep, b.rep, &x.rep); } inline void negate(ZZ& x, const ZZ& a) // x = -a { _ntl_gcopy(a.rep, &x.rep); _ntl_gnegate(&x.rep); } inline void abs(ZZ& x, const ZZ& a) // x = |a| { _ntl_gcopy(a.rep, &x.rep); _ntl_gabs(&x.rep); } /* single-precision versions of the above */ inline void add(ZZ& x, const ZZ& a, long b) { _ntl_gsadd(a.rep, b, &x.rep); } inline void add(ZZ& x, long a, const ZZ& b) { add(x, b, a); } inline void sub(ZZ& x, const ZZ& a, long b) { _ntl_gssub(a.rep, b, &x.rep); } void sub(ZZ& x, long a, const ZZ& b); // defined in ZZ.cpp /* operator/function notation */ inline ZZ operator+(const ZZ& a, const ZZ& b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator+(const ZZ& a, long b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator+(long a, const ZZ& b) { ZZ x; add(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a, const ZZ& b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a, long b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(long a, const ZZ& b) { ZZ x; sub(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator-(const ZZ& a) { ZZ x; negate(x, a); NTL_OPT_RETURN(ZZ, x); } inline ZZ abs(const ZZ& a) { ZZ x; abs(x, a); NTL_OPT_RETURN(ZZ, x); } /* op= notation */ inline ZZ& operator+=(ZZ& x, const ZZ& a) { add(x, x, a); return x; } inline ZZ& operator+=(ZZ& x, long a) { add(x, x, a); return x; } inline ZZ& operator-=(ZZ& x, const ZZ& a) { sub(x, x, a); return x; } inline ZZ& operator-=(ZZ& x, long a) { sub(x, x, a); return x; } /* inc/dec */ inline ZZ& operator++(ZZ& x) { add(x, x, 1); return x; } inline void operator++(ZZ& x, int) { add(x, x, 1); } inline ZZ& operator--(ZZ& x) { add(x, x, -1); return x; } inline void operator--(ZZ& x, int) { add(x, x, -1); } /******************************************************* Multiplication. ********************************************************/ inline void mul(ZZ& x, const ZZ& a, const ZZ& b) // x = a * b { _ntl_gmul(a.rep, b.rep, &x.rep); } inline void sqr(ZZ& x, const ZZ& a) // x = a*a { _ntl_gsq(a.rep, &x.rep); } inline ZZ sqr(const ZZ& a) { ZZ x; sqr(x, a); NTL_OPT_RETURN(ZZ, x); } /* single-precision versions */ inline void mul(ZZ& x, const ZZ& a, long b) { _ntl_gsmul(a.rep, b, &x.rep); } inline void mul(ZZ& x, long a, const ZZ& b) { mul(x, b, a); } /* operator notation */ inline ZZ operator*(const ZZ& a, const ZZ& b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator*(const ZZ& a, long b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator*(long a, const ZZ& b) { ZZ x; mul(x, a, b); NTL_OPT_RETURN(ZZ, x); } /* op= notation */ inline ZZ& operator*=(ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline ZZ& operator*=(ZZ& x, long a) { mul(x, x, a); return x; } // x += a*b inline void MulAddTo(ZZ& x, const ZZ& a, long b) { _ntl_gsaddmul(a.rep, b, &x.rep); } inline void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b) { _ntl_gaddmul(a.rep, b.rep, &x.rep); } // x -= a*b inline void MulSubFrom(ZZ& x, const ZZ& a, long b) { _ntl_gssubmul(a.rep, b, &x.rep); } inline void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b) { _ntl_gsubmul(a.rep, b.rep, &x.rep); } // Special routines for implementing CRT in ZZ_pX arithmetic // These are verbose, but fairly boilerplate class ZZ_CRTStructAdapter; class ZZ_RemStructAdapter; class ZZ_TmpVecAdapter { public: UniquePtr<_ntl_tmp_vec> rep; inline void fetch(const ZZ_CRTStructAdapter&); inline void fetch(ZZ_CRTStructAdapter&); inline void fetch(const ZZ_RemStructAdapter&); }; class ZZ_CRTStructAdapter { public: UniquePtr<_ntl_crt_struct> rep; void init(long n, const ZZ& p, long (*primes)(long)) { rep.reset(_ntl_crt_struct_build(n, p.rep, primes)); } void insert(long i, const ZZ& m) { rep->insert(i, m.rep); } void eval(ZZ& t, const long *a, ZZ_TmpVecAdapter& tmp_vec) const { rep->eval(&t.rep, a, tmp_vec.rep.get()); } bool special() const { return rep->special(); } }; class ZZ_RemStructAdapter { public: UniquePtr<_ntl_rem_struct> rep; void init(long n, const ZZ& p, long (*primes)(long)) { rep.reset(_ntl_rem_struct_build(n, p.rep, primes)); } void eval(long *x, const ZZ& a, ZZ_TmpVecAdapter& tmp_vec) const { rep->eval(x, a.rep, tmp_vec.rep.get()); } }; inline void ZZ_TmpVecAdapter::fetch(const ZZ_CRTStructAdapter& crt_struct) { rep.reset(crt_struct.rep->fetch()); } inline void ZZ_TmpVecAdapter::fetch(ZZ_CRTStructAdapter& crt_struct) { rep.reset(crt_struct.rep->extract()); // EXTRACT!! } inline void ZZ_TmpVecAdapter::fetch(const ZZ_RemStructAdapter& rem_struct) { rep.reset(rem_struct.rep->fetch()); } // montgomery class ZZ_ReduceStructAdapter { public: UniquePtr<_ntl_reduce_struct> rep; void init(const ZZ& p, const ZZ& excess) { rep.reset(_ntl_reduce_struct_build(p.rep, excess.rep)); } void eval(ZZ& x, ZZ& a) const { rep->eval(&x.rep, &a.rep); } void adjust(ZZ& x) const { rep->adjust(&x.rep); } }; /******************************************************* Division *******************************************************/ inline void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b) // q = [a/b], r = a - b*q // |r| < |b|, and if r != 0, sign(r) = sign(b) { _ntl_gdiv(a.rep, b.rep, &q.rep, &r.rep); } inline void div(ZZ& q, const ZZ& a, const ZZ& b) // q = a/b { _ntl_gdiv(a.rep, b.rep, &q.rep, 0); } inline void rem(ZZ& r, const ZZ& a, const ZZ& b) // r = a%b { _ntl_gmod(a.rep, b.rep, &r.rep); } inline void QuickRem(ZZ& r, const ZZ& b) // r = r%b // assumes b > 0 and r >=0 // division is performed in place and may cause r to be re-allocated. { _ntl_gquickmod(&r.rep, b.rep); } long divide(ZZ& q, const ZZ& a, const ZZ& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, const ZZ& b); // if b | a, returns 1; otherwise returns 0. /* non-standard single-precision versions */ inline long DivRem(ZZ& q, const ZZ& a, long b) { return _ntl_gsdiv(a.rep, b, &q.rep); } inline long rem(const ZZ& a, long b) { return _ntl_gsmod(a.rep, b); } /* single precision versions */ inline void div(ZZ& q, const ZZ& a, long b) { (void) _ntl_gsdiv(a.rep, b, &q.rep); } long divide(ZZ& q, const ZZ& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, long b); // if b | a, returns 1; otherwise returns 0. inline ZZ operator/(const ZZ& a, const ZZ& b) { ZZ x; div(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator/(const ZZ& a, long b) { ZZ x; div(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator%(const ZZ& a, const ZZ& b) { ZZ x; rem(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline long operator%(const ZZ& a, long b) { return rem(a, b); } inline ZZ& operator/=(ZZ& x, const ZZ& b) { div(x, x, b); return x; } inline ZZ& operator/=(ZZ& x, long b) { div(x, x, b); return x; } inline ZZ& operator%=(ZZ& x, const ZZ& b) { rem(x, x, b); return x; } // preconditioned single-precision variant // not documented for now... struct sp_ZZ_reduce_struct_policy { static void deleter(_ntl_general_rem_one_struct *pinfo) { _ntl_general_rem_one_struct_delete(pinfo); } }; struct sp_ZZ_reduce_struct { long p; UniquePtr<_ntl_general_rem_one_struct,sp_ZZ_reduce_struct_policy> pinfo; sp_ZZ_reduce_struct() : p(0) { } void build(long _p) { pinfo.reset(_ntl_general_rem_one_struct_build(_p)); p = _p; } long rem(const ZZ& a) const { return _ntl_general_rem_one_struct_apply(a.rep, p, pinfo.get()); } }; // special-purpose routines for accumulating CRT-like summations // Not documented for now. // Allocates sz+2 limbs and zeros them all out. // x is not normalized. inline void QuickAccumBegin(ZZ& x, long sz) { _ntl_quick_accum_begin(&x.rep, sz); } // x += y*b. // Assumes y >= 0 and that 0 <= b < NTL_SP_BOUND. // Caller must assure that x does not exceed sz+2 limbs. // x remains unnormalized. inline void QuickAccumMulAdd(ZZ& x, const ZZ& y, long b) { _ntl_quick_accum_muladd(x.rep, y.rep, b); } // renormalizes x. inline void QuickAccumEnd(ZZ& x) { _ntl_quick_accum_end(x.rep); } /********************************************************** GCD's ***********************************************************/ inline void GCD(ZZ& d, const ZZ& a, const ZZ& b) // d = gcd(a, b) { _ntl_ggcd(a.rep, b.rep, &d.rep); } inline ZZ GCD(const ZZ& a, const ZZ& b) { ZZ x; GCD(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline void GCD_alt(ZZ& d, const ZZ& a, const ZZ& b) // d = gcd(a, b) { _ntl_ggcd_alt(a.rep, b.rep, &d.rep); } inline void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b) // d = gcd(a, b) = a*s + b*t; { _ntl_gexteucl(a.rep, &s.rep, b.rep, &t.rep, &d.rep); } // single-precision versions long GCD(long a, long b); void XGCD(long& d, long& s, long& t, long a, long b); /************************************************************ Bit Operations *************************************************************/ inline void LeftShift(ZZ& x, const ZZ& a, long k) // x = (a << k), k < 0 => RightShift { _ntl_glshift(a.rep, k, &x.rep); } inline ZZ LeftShift(const ZZ& a, long k) { ZZ x; LeftShift(x, a, k); NTL_OPT_RETURN(ZZ, x); } inline void RightShift(ZZ& x, const ZZ& a, long k) // x = (a >> k), k < 0 => LeftShift { _ntl_grshift(a.rep, k, &x.rep); } inline ZZ RightShift(const ZZ& a, long k) { ZZ x; RightShift(x, a, k); NTL_OPT_RETURN(ZZ, x); } #ifndef NTL_TRANSITION inline ZZ operator>>(const ZZ& a, long n) { ZZ x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator<<(const ZZ& a, long n) { ZZ x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline ZZ& operator<<=(ZZ& x, long n) { LeftShift(x, x, n); return x; } inline ZZ& operator>>=(ZZ& x, long n) { RightShift(x, x, n); return x; } #endif inline long MakeOdd(ZZ& x) // removes factors of 2 from x, returns the number of 2's removed // returns 0 if x == 0 { return _ntl_gmakeodd(&x.rep); } inline long NumTwos(const ZZ& x) // returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0. { return _ntl_gnumtwos(x.rep); } inline long IsOdd(const ZZ& a) // returns 1 if a is odd, otherwise 0 { return _ntl_godd(a.rep); } inline long NumBits(const ZZ& a) // returns the number of bits in |a|; NumBits(0) = 0 { return _ntl_g2log(a.rep); } inline long bit(const ZZ& a, long k) // returns bit k of a, 0 being the low-order bit { return _ntl_gbit(a.rep, k); } #ifndef NTL_GMP_LIP // only defined for the "classic" long integer package, for backward // compatability. inline long digit(const ZZ& a, long k) { return _ntl_gdigit(a.rep, k); } #endif // returns k-th digit of |a|, 0 being the low-order digit. inline void trunc(ZZ& x, const ZZ& a, long k) // puts k low order bits of |a| into x { _ntl_glowbits(a.rep, k, &x.rep); } inline ZZ trunc_ZZ(const ZZ& a, long k) { ZZ x; trunc(x, a, k); NTL_OPT_RETURN(ZZ, x); } inline long trunc_long(const ZZ& a, long k) // returns k low order bits of |a| { return _ntl_gslowbits(a.rep, k); } inline long SetBit(ZZ& x, long p) // returns original value of p-th bit of |a|, and replaces // p-th bit of a by 1 if it was zero; // error if p < 0 { return _ntl_gsetbit(&x.rep, p); } inline long SwitchBit(ZZ& x, long p) // returns original value of p-th bit of |a|, and switches // the value of p-th bit of a; // p starts counting at 0; // error if p < 0 { return _ntl_gswitchbit(&x.rep, p); } inline long weight(long a) // returns Hamming weight of |a| { return _ntl_gweights(a); } inline long weight(const ZZ& a) // returns Hamming weight of |a| { return _ntl_gweight(a.rep); } inline void bit_and(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| AND |b| { _ntl_gand(a.rep, b.rep, &x.rep); } void bit_and(ZZ& x, const ZZ& a, long b); inline void bit_and(ZZ& x, long a, const ZZ& b) { bit_and(x, b, a); } inline void bit_or(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| OR |b| { _ntl_gor(a.rep, b.rep, &x.rep); } void bit_or(ZZ& x, const ZZ& a, long b); inline void bit_or(ZZ& x, long a, const ZZ& b) { bit_or(x, b, a); } inline void bit_xor(ZZ& x, const ZZ& a, const ZZ& b) // x = |a| XOR |b| { _ntl_gxor(a.rep, b.rep, &x.rep); } void bit_xor(ZZ& x, const ZZ& a, long b); inline void bit_xor(ZZ& x, long a, const ZZ& b) { bit_xor(x, b, a); } inline ZZ operator&(const ZZ& a, const ZZ& b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator&(const ZZ& a, long b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator&(long a, const ZZ& b) { ZZ x; bit_and(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(const ZZ& a, const ZZ& b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(const ZZ& a, long b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator|(long a, const ZZ& b) { ZZ x; bit_or(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(const ZZ& a, const ZZ& b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(const ZZ& a, long b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ operator^(long a, const ZZ& b) { ZZ x; bit_xor(x, a, b); NTL_OPT_RETURN(ZZ, x); } inline ZZ& operator&=(ZZ& x, const ZZ& b) { bit_and(x, x, b); return x; } inline ZZ& operator&=(ZZ& x, long b) { bit_and(x, x, b); return x; } inline ZZ& operator|=(ZZ& x, const ZZ& b) { bit_or(x, x, b); return x; } inline ZZ& operator|=(ZZ& x, long b) { bit_or(x, x, b); return x; } inline ZZ& operator^=(ZZ& x, const ZZ& b) { bit_xor(x, x, b); return x; } inline ZZ& operator^=(ZZ& x, long b) { bit_xor(x, x, b); return x; } inline long NumBits(long a) { return _ntl_g2logs(a); } long bit(long a, long k); long NextPowerOfTwo(long m); // returns least nonnegative k such that 2^k >= m inline long NumBytes(const ZZ& a) { return (NumBits(a)+7)/8; } inline long NumBytes(long a) { return (NumBits(a)+7)/8; } /*********************************************************** Some specialized routines ************************************************************/ inline long ZZ_BlockConstructAlloc(ZZ& x, long d, long n) { return _ntl_gblock_construct_alloc(&x.rep, d, n); } inline void ZZ_BlockConstructSet(ZZ& x, ZZ& y, long i) { _ntl_gblock_construct_set(x.rep, &y.rep, i); } inline long ZZ_BlockDestroy(ZZ& x) { return _ntl_gblock_destroy(x.rep); } inline long ZZ_storage(long d) { return _ntl_gblock_storage(d); } inline long ZZ_RoundCorrection(const ZZ& a, long k, long residual) { return _ntl_ground_correction(a.rep, k, residual); } /*********************************************************** Psuedo-random Numbers ************************************************************/ // ================ NEW PRG STUFF ================= // Low-level key-derivation void DeriveKey(unsigned char *key, long klen, const unsigned char *data, long dlen); // Low-level chacha stuff #define NTL_PRG_KEYLEN (32) struct RandomStream_impl; RandomStream_impl * RandomStream_impl_build(const unsigned char *key); RandomStream_impl * RandomStream_impl_build(const RandomStream_impl&); void RandomStream_impl_copy(RandomStream_impl&, const RandomStream_impl&); const unsigned char * RandomStream_impl_get_buf(const RandomStream_impl&); long RandomStream_impl_get_buf_len(const RandomStream_impl&); long RandomStream_impl_get_bytes(RandomStream_impl& impl, unsigned char *res, long n, long pos); void RandomStream_impl_set_nonce(RandomStream_impl& impl, unsigned long nonce); void RandomStream_impl_delete(RandomStream_impl*); struct RandomStream_impl_deleter { static void deleter(RandomStream_impl* p) { RandomStream_impl_delete(p); } }; class RandomStream { private: long pos; const unsigned char *buf; long buf_len; UniquePtr impl; public: explicit RandomStream(const unsigned char *key) { impl.reset(RandomStream_impl_build(key)); pos = buf_len = RandomStream_impl_get_buf_len(*impl); buf = RandomStream_impl_get_buf(*impl); } RandomStream(const RandomStream& other) { impl.reset(RandomStream_impl_build(*other.impl)); pos = other.pos; buf_len = other.buf_len; buf = RandomStream_impl_get_buf(*impl); } RandomStream& operator=(const RandomStream& other) { RandomStream_impl_copy(*impl, *other.impl); pos = other.pos; buf_len = other.buf_len; buf = RandomStream_impl_get_buf(*impl); return *this; } void get(unsigned char *res, long n) { // optimize short reads if (n > 0 && n <= buf_len-pos) { #if 1 std::memcpy(&res[0], &buf[pos], n); // NOTE: mempy undefined if res == null // That's a reason we don't do this for n==0, which // is anyway an unlikely case #else for (long i = 0; i < n; i++) { res[i] = buf[pos+i]; } #endif pos += n; } else { pos = RandomStream_impl_get_bytes(*impl, res, n, pos); } } // FIXME: document this? Not sure if I want to // commit to this interface, as it is somewhat ChaCha-specific void set_nonce(unsigned long nonce) { RandomStream_impl_set_nonce(*impl, nonce); pos = buf_len; } }; // this is the number of bits we can pass through the set_nonce // interface #if (NTL_BITS_PER_LONG > 64) #define NTL_BITS_PER_NONCE (64) #else #define NTL_BITS_PER_NONCE NTL_BITS_PER_LONG #endif // ============ old stuff: for testing ============ class old_RandomStream { private: _ntl_uint32 state[16]; unsigned char buf[64]; long pos; void do_get(unsigned char *res, long n); public: explicit old_RandomStream(const unsigned char *key); // No default constructor // default copy and assignment void get(unsigned char *res, long n) { // optimize short reads if (n >= 0 && n <= 64-pos) { long i; for (i = 0; i < n; i++) { res[i] = buf[pos+i]; } pos += n; } else { do_get(res, n); } } }; RandomStream& GetCurrentRandomStream(); // get reference to the current random by stream -- // if SetSeed has not been called, it is called with // a default value (which should be unique to each // process/thread void SetSeed(const ZZ& s); void SetSeed(const unsigned char *data, long dlen); void SetSeed(const RandomStream& s); // initialize random number generator // in the first two version, a PRG key is derived from // the data using DeriveKey. // RAII for saving/restoring current state of PRG class RandomStreamPush { private: RandomStream saved; RandomStreamPush(const RandomStreamPush&); // disable void operator=(const RandomStreamPush&); // disable public: RandomStreamPush() : saved(GetCurrentRandomStream()) { } ~RandomStreamPush() { SetSeed(saved); } }; void RandomBnd(ZZ& x, const ZZ& n); // x = "random number" in the range 0..n-1, or 0 if n <= 0 inline ZZ RandomBnd(const ZZ& n) { ZZ x; RandomBnd(x, n); NTL_OPT_RETURN(ZZ, x); } void RandomLen(ZZ& x, long NumBits); // x = "random number" with precisely NumBits bits. inline ZZ RandomLen_ZZ(long NumBits) { ZZ x; RandomLen(x, NumBits); NTL_OPT_RETURN(ZZ, x); } void RandomBits(ZZ& x, long NumBits); // x = "random number", 0 <= x < 2^NumBits inline ZZ RandomBits_ZZ(long NumBits) { ZZ x; RandomBits(x, NumBits); NTL_OPT_RETURN(ZZ, x); } // single-precision version of the above long RandomBnd(long n); inline void RandomBnd(long& x, long n) { x = RandomBnd(n); } long RandomLen_long(long l); inline void RandomLen(long& x, long l) { x = RandomLen_long(l); } long RandomBits_long(long l); inline void RandomBits(long& x, long l) { x = RandomBits_long(l); } // specialty routines unsigned long RandomWord(); unsigned long RandomBits_ulong(long l); // helper class to make generating small random numbers faster // FIXME: add documentation? struct RandomBndGenerator { long p; long nb; unsigned long mask; RandomStream *str; RandomBndGenerator() : p(0) { } explicit RandomBndGenerator(long _p) : p(0) { build(_p); } void build(long _p) { if (_p <= 1) LogicError("RandomBndGenerator::init: bad args"); if (!p) { str = &GetCurrentRandomStream(); } p = _p; long l = NumBits(p-1); nb = (l+7)/8; mask = (1UL << l)-1UL; } long next() { unsigned char buf[NTL_BITS_PER_LONG/8]; long tmp; do { str->get(buf, nb); unsigned long word = 0; for (long i = nb-1; i >= 0; i--) word = (word << 8) | buf[i]; tmp = long(word & mask); } while (tmp >= p); return tmp; } }; inline void VectorRandomBnd(long k, long* x, long n) { if (k <= 0) return; if (n <= 1) { for (long i = 0; i < k; i++) x[i] = 0; } else { RandomBndGenerator gen(n); for (long i = 0; i < k; i++) x[i] = gen.next(); } } void VectorRandomWord(long k, unsigned long* x); /********************************************************** Incremental Chinese Remaindering ***********************************************************/ long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P); long CRT(ZZ& a, ZZ& p, long A, long P); // 0 <= A < P, (p, P) = 1; // computes b such that b = a mod p, b = A mod p, // and -p*P/2 < b <= p*P/2; // sets a = b, p = p*P, and returns 1 if a's value // has changed, otherwise 0 inline long CRTInRange(const ZZ& gg, const ZZ& aa) { return _ntl_gcrtinrange(gg.rep, aa.rep); } // an auxilliary routine used by newer CRT routines to maintain // backward compatability. // test if a > 0 and -a/2 < g <= a/2 // this is "hand crafted" so as not too waste too much time // in the CRT routines. /********************************************************** Rational Reconstruction ***********************************************************/ inline long ReconstructRational(ZZ& a, ZZ& b, const ZZ& u, const ZZ& m, const ZZ& a_bound, const ZZ& b_bound) { return _ntl_gxxratrecon(u.rep, m.rep, a_bound.rep, b_bound.rep, &a.rep, &b.rep); } /************************************************************ Primality Testing *************************************************************/ void GenPrime(ZZ& n, long l, long err = 80); inline ZZ GenPrime_ZZ(long l, long err = 80) { ZZ x; GenPrime(x, l, err); NTL_OPT_RETURN(ZZ, x); } long GenPrime_long(long l, long err = 80); // This generates a random prime n of length l so that the // probability of erroneously returning a composite is bounded by 2^(-err). void GenGermainPrime(ZZ& n, long l, long err = 80); inline ZZ GenGermainPrime_ZZ(long l, long err = 80) { ZZ x; GenGermainPrime(x, l, err); NTL_OPT_RETURN(ZZ, x); } long GenGermainPrime_long(long l, long err = 80); // This generates a random prime n of length l so that the long ProbPrime(const ZZ& n, long NumTrials = 10); // tests if n is prime; performs a little trial division, // followed by a single-precision MillerWitness test, followed by // up to NumTrials general MillerWitness tests. long MillerWitness(const ZZ& n, const ZZ& w); // Tests if w is a witness to primality a la Miller. // Assumption: n is odd and positive, 0 <= w < n. void RandomPrime(ZZ& n, long l, long NumTrials=10); // n = random l-bit prime inline ZZ RandomPrime_ZZ(long l, long NumTrials=10) { ZZ x; RandomPrime(x, l, NumTrials); NTL_OPT_RETURN(ZZ, x); } void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10); // n = smallest prime >= m. inline ZZ NextPrime(const ZZ& m, long NumTrials=10) { ZZ x; NextPrime(x, m, NumTrials); NTL_OPT_RETURN(ZZ, x); } // single-precision versions long ProbPrime(long n, long NumTrials = 10); long RandomPrime_long(long l, long NumTrials=10); long NextPrime(long l, long NumTrials=10); /************************************************************ Exponentiation *************************************************************/ inline void power(ZZ& x, const ZZ& a, long e) { _ntl_gexp(a.rep, e, &x.rep); } inline ZZ power(const ZZ& a, long e) { ZZ x; power(x, a, e); NTL_OPT_RETURN(ZZ, x); } inline void power(ZZ& x, long a, long e) { _ntl_gexps(a, e, &x.rep); } inline ZZ power_ZZ(long a, long e) { ZZ x; power(x, a, e); NTL_OPT_RETURN(ZZ, x); } long power_long(long a, long e); void power2(ZZ& x, long e); inline ZZ power2_ZZ(long e) { ZZ x; power2(x, e); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Square Roots **************************************************************/ inline void SqrRoot(ZZ& x, const ZZ& a) // x = [a^{1/2}], a >= 0 { _ntl_gsqrt(a.rep, &x.rep); } inline ZZ SqrRoot(const ZZ& a) { ZZ x; SqrRoot(x, a); NTL_OPT_RETURN(ZZ, x); } inline long SqrRoot(long a) { return _ntl_gsqrts(a); } // single-precision version /*************************************************************** Modular Arithmetic ***************************************************************/ // The following routines perform arithmetic mod n, n positive. // All args (other than exponents) are assumed to be in the range 0..n-1. inline void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a+b)%n { _ntl_gaddmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a-b)%n { _ntl_gsubmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void NegateMod(ZZ& x, const ZZ& a, const ZZ& n) // x = -a % n { _ntl_gsubmod(0, a.rep, n.rep, &x.rep); } inline ZZ NegateMod(const ZZ& a, const ZZ& n) { ZZ x; NegateMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } void AddMod(ZZ& x, const ZZ& a, long b, const ZZ& n); inline ZZ AddMod(const ZZ& a, long b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void AddMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { AddMod(x, b, a, n); } inline ZZ AddMod(long a, const ZZ& b, const ZZ& n) { ZZ x; AddMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } void SubMod(ZZ& x, const ZZ& a, long b, const ZZ& n); inline ZZ SubMod(const ZZ& a, long b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } void SubMod(ZZ& x, long a, const ZZ& b, const ZZ& n); inline ZZ SubMod(long a, const ZZ& b, const ZZ& n) { ZZ x; SubMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n) // x = (a*b)%n { _ntl_gmulmod(a.rep, b.rep, n.rep, &x.rep); } inline ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, const ZZ& a, long b, const ZZ& n) // x = (a*b)%n { _ntl_gsmulmod(a.rep, b, n.rep, &x.rep); } inline ZZ MulMod(const ZZ& a, long b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void MulMod(ZZ& x, long a, const ZZ& b, const ZZ& n) { MulMod(x, b, a, n); } inline ZZ MulMod(long a, const ZZ& b, const ZZ& n) { ZZ x; MulMod(x, a, b, n); NTL_OPT_RETURN(ZZ, x); } inline void SqrMod(ZZ& x, const ZZ& a, const ZZ& n) // x = a^2 % n { _ntl_gsqmod(a.rep, n.rep, &x.rep); } inline ZZ SqrMod(const ZZ& a, const ZZ& n) { ZZ x; SqrMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } void InvMod(ZZ& x, const ZZ& a, const ZZ& n); // defined in ZZ.c in terms of InvModStatus inline ZZ InvMod(const ZZ& a, const ZZ& n) { ZZ x; InvMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } inline long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n) // if gcd(a,n) = 1, then ReturnValue = 0, x = a^{-1} mod n // otherwise, ReturnValue = 1, x = gcd(a, n) { return _ntl_ginv(a.rep, n.rep, &x.rep); } void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n); // defined in ZZ.c in terms of LowLevelPowerMod inline void LowLevelPowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n) { _ntl_gpowermod(a.rep, e.rep, n.rep, &x.rep); } inline ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n) { ZZ x; PowerMod(x, a, e, n); NTL_OPT_RETURN(ZZ, x); } inline void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n) { PowerMod(x, a, ZZ_expo(e), n); } inline ZZ PowerMod(const ZZ& a, long e, const ZZ& n) { ZZ x; PowerMod(x, a, e, n); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Jacobi symbol and modular squre roots **************************************************************/ long Jacobi(const ZZ& a, const ZZ& n); // compute Jacobi symbol of a and n; // assumes 0 <= a < n, n odd void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n); // computes square root of a mod n; // assumes n is an odd prime, and that a is a square mod n inline ZZ SqrRootMod(const ZZ& a, const ZZ& n) { ZZ x; SqrRootMod(x, a, n); NTL_OPT_RETURN(ZZ, x); } /************************************************************* Small Prime Generation *************************************************************/ // primes are generated in sequence, starting at 2, // and up until (2*NTL_PRIME_BND+1)^2, which is less than NTL_SP_BOUND. #if (NTL_SP_NBITS > 30) #define NTL_PRIME_BND ((1L << 14) - 1) #else #define NTL_PRIME_BND ((1L << (NTL_SP_NBITS/2-1)) - 1) #endif class PrimeSeq { const char *movesieve; Vec movesieve_mem; long pindex; long pshift; long exhausted; public: PrimeSeq(); long next(); // returns next prime in the sequence. // returns 0 if list of small primes is exhausted. void reset(long b); // resets generator so that the next prime in the sequence // is the smallest prime >= b. private: PrimeSeq(const PrimeSeq&); // disabled void operator=(const PrimeSeq&); // disabled // auxilliary routines void start(); void shift(long); }; /************************************************************** Input/Output ***************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ& a); // Some additional SP arithmetic routines, not defined in sp_arith.h long InvMod(long a, long n); // computes a^{-1} mod n. Error is raised if undefined. long InvModStatus(long& x, long a, long n); // if gcd(a,n) = 1, then ReturnValue = 0, x = a^{-1} mod n // otherwise, ReturnValue = 1, x = gcd(a, n) long PowerMod(long a, long e, long n); // computes a^e mod n, e >= 0 // Error handling #ifdef NTL_EXCEPTIONS class InvModErrorObject : public ArithmeticErrorObject { private: SmartPtr a_ptr; SmartPtr n_ptr; public: InvModErrorObject(const char *s, const ZZ& a, const ZZ& n) : ArithmeticErrorObject(s) , a_ptr(MakeSmart(a)), n_ptr(MakeSmart(n)) { } const ZZ& get_a() const { return *a_ptr; } const ZZ& get_n() const { return *n_ptr; } }; #else // We need this alt definition to keep pre-C++11 // compilers happy (NTL_EXCEPTIONS should only be used // with C++11 compilers). class InvModErrorObject : public ArithmeticErrorObject { public: InvModErrorObject(const char *s, const ZZ& a, const ZZ& n) : ArithmeticErrorObject(s) { } const ZZ& get_a() const { return ZZ::zero(); } const ZZ& get_n() const { return ZZ::zero(); } }; #endif void InvModError(const char *s, const ZZ& a, const ZZ& n); #ifdef NTL_PROVIDES_SS_LIP_IMPL inline void LeftRotate_lip_impl(ZZ& a, const ZZ& b, long e, const ZZ& p, long n, ZZ& scratch) // Compute a = b * 2^e mod p, where p = 2^n+1. 0<=e #ifdef NTL_GMP_LIP #include #endif #ifdef NTL_GMP_LIP typedef mp_limb_t _ntl_limb_t; #else typedef unsigned long _ntl_limb_t; #define NTL_BITS_PER_LIMB_T NTL_BITS_PER_LONG #endif void _ntl_glimbs_set(const _ntl_limb_t *p, long n, _ntl_gbigint *x); // DIRT: This exposes some internals that shoup be in lip.cpp, // but are here to make it inline. inline const _ntl_limb_t * _ntl_glimbs_get(_ntl_gbigint p) { return p ? ((_ntl_limb_t *) (((long *) (p)) + 2)) : 0; } NTL_OPEN_NNS typedef _ntl_limb_t ZZ_limb_t; inline void ZZ_limbs_set(ZZ& x, const ZZ_limb_t *p, long n) { _ntl_glimbs_set(p, n, &x.rep); } inline const ZZ_limb_t * ZZ_limbs_get(const ZZ& a) { return _ntl_glimbs_get(a.rep); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/sp_arith.h0000644417616742025610000005737214064716022020235 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_sp_arith__H #define NTL_sp_arith__H /**************************************************************** Single-precision modular arithmetic *****************************************************************/ /* these routines implement single-precision modular arithmetic. If n is the modulus, all inputs should be in the range 0..n-1. The number n itself should be in the range 1..2^{NTL_SP_NBITS}-1. */ // DIRT: undocumented feature: in all of these MulMod routines, // the first argument, a, need only be in the range // 0..2^{NTL_SP_NBITS}-1. This is assumption is used internally // in some NT routines...I've tried to mark all such uses with a // DIRT comment. I may decide to make this feature part // of the documented interface at some point in the future. // NOTE: this header file is for internal use only, via the ZZ.h header. // It is also used in the LIP implementation files c/g_lip_impl.h. #include #include NTL_OPEN_NNS #define NTL_HAVE_MULMOD_T #if (defined(NTL_SPMM_ULL) && defined(NTL_HAVE_LL_TYPE)) // we only honor SPMM_ULL if we have LL #define NTL_SPMM_ULL_VIABLE #elif (defined(NTL_SPMM_ULL) && defined(NTL_WIZARD_HACK)) // raise an error when running the wizard and we cannot honor SPMM_ULL #error "cannot honor NTL_SPMM_ULL" #endif #if 0 // the following code can be used to use new-style clients with old versions // of NTL #ifndef NTL_HAVE_MULMOD_T NTL_OPEN_NNS typedef double mulmod_t; typedef double muldivrem_t; inline double PrepMulMod(long n) { return double(1L)/double(n); } inline double PrepMulDivRem(long b, long n, double ninv) { return double(b)*ninv; } inline double PrepMulDivRem(long b, long n) { return double(b)/double(n); } inline double PrepMulModPrecon(long b, long n) { return PrepMulModPrecon(b, n, PrepMulMod(n)); } NTL_CLOSE_NNS #endif #endif /********************************************************* HELPER ROUTINES: long sp_SignMask(long a) long sp_SignMask(unsigned long a) // if (long(a) < 0) then -1 else 0 bool sp_Negative(unsigned long a) // long(a) < 0 long sp_CorrectDeficit(long a, long n) long sp_CorrectDeficit(unsigned long a, long n): // if (long(a) >= 0) then a else a+n // it is assumed that n in (0..B), where B = 2^(NTL_BITS_PER_LONG-1), // and that long(a) >= -n long sp_CorrectExcess(long a, long n) long sp_CorrectExcess(unsigned long a, long n): // if (a < n) then a else a-n // For the signed version, it is assumed that a >= 0. // In either version, it is assumed that // n in (0..B) and a-n in (-B..B). These are designed to respect the flags NTL_CLEAN_INT, NTL_ARITH_RIGHT_SHIFT, and NTL_AVOID_BRANCHING. *********************************************************/ #if (NTL_ARITH_RIGHT_SHIFT && !defined(NTL_CLEAN_INT)) // DIRT: IMPL-DEF: arithmetic right shift and cast unsigned to signed inline long sp_SignMask(long a) { return a >> (NTL_BITS_PER_LONG-1); } inline long sp_SignMask(unsigned long a) { return cast_signed(a) >> (NTL_BITS_PER_LONG-1); } #else inline long sp_SignMask(long a) { return -long(cast_unsigned(a) >> (NTL_BITS_PER_LONG-1)); } inline long sp_SignMask(unsigned long a) { return -long(a >> (NTL_BITS_PER_LONG-1)); } #endif inline bool sp_Negative(unsigned long a) { return cast_signed(a) < 0; } #if (!defined(NTL_AVOID_BRANCHING)) // The C++ code is written using branching, but // on machines with large branch penalties, this code // should yield "predicated instructions" (i.e., on x86, // conditional moves). The "branching" version of sp_CorrectExcess // in written in a particular way to get optimal machine code: // subtract, cmove (tested on clang, gcc, icc). inline long sp_CorrectDeficit(long a, long n) { return a >= 0 ? a : a+n; } template long sp_CorrectDeficitQuo(T& q, long a, long n, long amt=1) { return a >= 0 ? a : (q -= amt, a+n); } inline long sp_CorrectDeficit(unsigned long a, long n) { return !sp_Negative(a) ? a : a+n; } template long sp_CorrectDeficitQuo(T& q, unsigned long a, long n, long amt=1) { return !sp_Negative(a) ? a : (q -= amt, a+n); } inline long sp_CorrectExcess(long a, long n) { return a-n >= 0 ? a-n : a; } template long sp_CorrectExcessQuo(T& q, long a, long n, long amt=1) { return a-n >= 0 ? (q += amt, a-n) : a; } inline long sp_CorrectExcess(unsigned long a, long n) { return !sp_Negative(a-n) ? a-n : a; } template long sp_CorrectExcessQuo(T& q, unsigned long a, long n, long amt=1) { return !sp_Negative(a-n) ? (q += amt, a-n) : a; } #else // This C++ code uses traditional masking and adding // to avoid branching. inline long sp_CorrectDeficit(long a, long n) { return a + (sp_SignMask(a) & n); } template long sp_CorrectDeficitQuo(T& q, long a, long n, long amt=1) { q += sp_SignMask(a)*amt; return a + (sp_SignMask(a) & n); } inline long sp_CorrectDeficit(unsigned long a, long n) { return a + (sp_SignMask(a) & n); } template long sp_CorrectDeficitQuo(T& q, unsigned long a, long n, long amt=1) { q += sp_SignMask(a)*amt; return a + (sp_SignMask(a) & n); } inline long sp_CorrectExcess(long a, long n) { return (a-n) + (sp_SignMask(a-n) & n); } template long sp_CorrectExcessQuo(T& q, long a, long n, long amt=1) { q += (1L + sp_SignMask(a-n))*amt; return (a-n) + (sp_SignMask(a-n) & n); } inline long sp_CorrectExcess(unsigned long a, long n) { return (a-n) + (sp_SignMask(a-n) & n); } template long sp_CorrectExcessQuo(T& q, unsigned long a, long n, long amt=1) { q += (1L + sp_SignMask(a-n))*amt; return (a-n) + (sp_SignMask(a-n) & n); } #endif // ********************************************************************** #ifdef NTL_HAVE_BUILTIN_CLZL inline long sp_CountLeadingZeros(unsigned long x) { return __builtin_clzl(x); } #else inline long sp_CountLeadingZeros(unsigned long x) { long res = NTL_BITS_PER_LONG-NTL_SP_NBITS; x = x << (NTL_BITS_PER_LONG-NTL_SP_NBITS); while (x < (1UL << (NTL_BITS_PER_LONG-1))) { x <<= 1; res++; } return res; } #endif inline long AddMod(long a, long b, long n) { long r = a+b; return sp_CorrectExcess(r, n); } inline long SubMod(long a, long b, long n) { long r = a-b; return sp_CorrectDeficit(r, n); } inline long NegateMod(long a, long n) { return SubMod(0, a, n); } #if (!defined(NTL_LONGLONG_SP_MULMOD)) #ifdef NTL_LEGACY_SP_MULMOD #define NTL_WIDE_DOUBLE_PRECISION NTL_DOUBLE_PRECISION #define NTL_WIDE_FDOUBLE_PRECISION NTL_WIDE_DOUBLE_DP typedef double wide_double; #else #ifdef NTL_LONGDOUBLE_SP_MULMOD #define NTL_WIDE_DOUBLE_PRECISION NTL_LONGDOUBLE_PRECISION #define NTL_WIDE_FDOUBLE_PRECISION NTL_WIDE_DOUBLE_LDP typedef long double wide_double_impl_t; #else #define NTL_WIDE_DOUBLE_PRECISION NTL_DOUBLE_PRECISION #define NTL_WIDE_FDOUBLE_PRECISION NTL_WIDE_DOUBLE_DP typedef double wide_double_impl_t; #endif class wide_double { public: wide_double_impl_t data; wide_double() { } wide_double(const wide_double& x) : data(x.data) { } template explicit wide_double(const T& x) : data(x) { } operator wide_double_impl_t() const { return data; } }; inline wide_double operator+(wide_double x, wide_double y) { return wide_double(x.data + y.data); } inline wide_double operator-(wide_double x, wide_double y) { return wide_double(x.data - y.data); } inline wide_double operator*(wide_double x, wide_double y) { return wide_double(x.data * y.data); } inline wide_double operator/(wide_double x, wide_double y) { return wide_double(x.data / y.data); } inline wide_double floor(wide_double x) { return wide_double(std::floor(x.data)); } inline wide_double& operator+=(wide_double& x, wide_double y) { return x = x + y; } inline wide_double& operator-=(wide_double& x, wide_double y) { return x = x - y; } inline wide_double& operator*=(wide_double& x, wide_double y) { return x = x * y; } inline wide_double& operator/=(wide_double& x, wide_double y) { return x = x / y; } #endif // old-style MulMod code using floating point arithmetic typedef wide_double mulmod_t; typedef wide_double muldivrem_t; inline wide_double PrepMulMod(long n) { return wide_double(1L)/wide_double(n); } inline wide_double PrepMulDivRem(long b, long n, wide_double ninv) { return wide_double(b)*ninv; } inline long MulMod(long a, long b, long n, wide_double ninv) { long q = long( wide_double(a) * (wide_double(b) * ninv) ); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficit(rr, n); return sp_CorrectExcess(r, n); } inline long NormalizedMulMod(long a, long b, long n, wide_double ninv) { return MulMod(a, b, n, ninv); } inline bool NormalizedModulus(wide_double ninv) { return true; } inline long MulModWithQuo(long& qres, long a, long b, long n, wide_double ninv) { long q = (long) ((((wide_double) a) * ((wide_double) b)) * ninv); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficitQuo(q, rr, n); r = sp_CorrectExcessQuo(q, r, n); qres = q; return r; } inline long MulMod2_legacy(long a, long b, long n, wide_double bninv) { long q = (long) (((wide_double) a) * bninv); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficit(rr, n); r = sp_CorrectExcess(r, n); return r; } inline long MulDivRem(long& qres, long a, long b, long n, wide_double bninv) { long q = (long) (((wide_double) a) * bninv); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - cast_unsigned(q)*cast_unsigned(n); long r = sp_CorrectDeficitQuo(q, rr, n); r = sp_CorrectExcessQuo(q, r, n); qres = q; return r; } #else // new-style MulMod code using ULL arithmetic struct sp_inverse { unsigned long inv; long shamt; sp_inverse() NTL_DEFAULT sp_inverse(unsigned long _inv, long _shamt) : inv(_inv), shamt(_shamt) { } }; typedef sp_inverse mulmod_t; #if (NTL_BITS_PER_LONG >= NTL_SP_NBITS+4) #define NTL_PRE_SHIFT1 (NTL_BITS_PER_LONG-NTL_SP_NBITS-4) #define NTL_POST_SHIFT (0) #define NTL_PRE_SHIFT2 (2*NTL_SP_NBITS+2) #else // DIRT: This assumes NTL_BITS_PER_LONG == NTL_SP_NBITS+2. // There are checks in lip.h to verify this. #define NTL_PRE_SHIFT1 (0) #define NTL_POST_SHIFT (1) #define NTL_PRE_SHIFT2 (2*NTL_SP_NBITS+1) #endif #if (NTL_SP_NBITS <= 2*NTL_DOUBLE_PRECISION-10) inline unsigned long sp_NormalizedPrepMulMod(long n) { double ninv = 1/double(n); unsigned long nn = n; // initial approximation to quotient unsigned long qq = long((double(1L << (NTL_SP_NBITS-1)) * double(1L << NTL_SP_NBITS)) * ninv); // NOTE: the true quotient is <= 2^{NTL_SP_NBITS} // compute approximate remainder using ULL arithmetic NTL_ULL_TYPE rr = (((NTL_ULL_TYPE)(1)) << (2*NTL_SP_NBITS-1)) - (((NTL_ULL_TYPE)(nn)) * ((NTL_ULL_TYPE)(qq))); rr = (rr << (NTL_PRE_SHIFT2-2*NTL_SP_NBITS+1)) - 1; // now compute a floating point approximation to r, // but avoiding unsigned -> float conversions, // as these are not as well supported in hardware as // signed -> float conversions unsigned long rrlo = (unsigned long) rr; unsigned long rrhi = ((unsigned long) (rr >> NTL_BITS_PER_LONG)) + (rrlo >> (NTL_BITS_PER_LONG-1)); long rlo = cast_signed(rrlo); // these should be No-Ops long rhi = cast_signed(rrhi); const double bpl_as_double (double(1L << NTL_SP_NBITS) * double(1L << (NTL_BITS_PER_LONG-NTL_SP_NBITS))); double fr = double(rlo) + double(rhi)*bpl_as_double; // now convert fr*ninv to a long // but we have to be careful: fr may be negative. // the result should still give floor(r/n) pm 1, // and is computed in a way that avoids branching long q1 = long(fr*ninv); if (q1 < 0) q1--; // This counteracts the round-to-zero behavior of conversion // to long. It should be compiled into branch-free code. unsigned long qq1 = q1; unsigned long rr1 = rrlo - qq1*nn; qq1 += 1L + sp_SignMask(rr1) + sp_SignMask(rr1-n); unsigned long res = (qq << (NTL_PRE_SHIFT2-2*NTL_SP_NBITS+1)) + qq1; res = res << NTL_PRE_SHIFT1; return res; } #else inline unsigned long sp_NormalizedPrepMulMod(long n) { return (((unsigned long) ( ((((NTL_ULL_TYPE) 1) << NTL_PRE_SHIFT2) - 1)/n )) << NTL_PRE_SHIFT1); } #endif inline sp_inverse PrepMulMod(long n) { long shamt = sp_CountLeadingZeros(n) - (NTL_BITS_PER_LONG-NTL_SP_NBITS); unsigned long inv = sp_NormalizedPrepMulMod(n << shamt); return sp_inverse(inv, shamt); } inline long sp_NormalizedMulMod(long a, long b, long n, unsigned long ninv) { ll_type U; ll_imul(U, a, b); unsigned long H = ll_rshift_get_lo(U); unsigned long Q = ll_mul_hi(H, ninv); Q = Q >> NTL_POST_SHIFT; unsigned long L = ll_get_lo(U); long r = L - Q*cast_unsigned(n); // r in [0..2*n) r = sp_CorrectExcess(r, n); return r; } inline long MulMod(long a, long b, long n, sp_inverse ninv) { return sp_NormalizedMulMod(a, b << ninv.shamt, n << ninv.shamt, ninv.inv) >> ninv.shamt; } // if you know what you're doing.... // FIXME: eventually, put this is the documented interface... // but for now, it's "experimental" inline long NormalizedMulMod(long a, long b, long n, sp_inverse ninv) { return sp_NormalizedMulMod(a, b, n, ninv.inv); } inline bool NormalizedModulus(sp_inverse ninv) { return ninv.shamt == 0; } inline long sp_NormalizedMulModWithQuo(long& qres, long a, long b, long n, unsigned long ninv) { ll_type U; ll_imul(U, a, b); unsigned long H = ll_rshift_get_lo(U); unsigned long Q = ll_mul_hi(H, ninv); Q = Q >> NTL_POST_SHIFT; unsigned long L = ll_get_lo(U); long r = L - Q*cast_unsigned(n); // r in [0..2*n) r = sp_CorrectExcessQuo(Q, r, n); qres = Q; return r; } inline long MulModWithQuo(long& qres, long a, long b, long n, sp_inverse ninv) { return sp_NormalizedMulModWithQuo(qres, a, b << ninv.shamt, n << ninv.shamt, ninv.inv) >> ninv.shamt; } #endif #if (defined(NTL_SPMM_ULL_VIABLE) || defined(NTL_LONGLONG_SP_MULMOD)) typedef unsigned long mulmod_precon_t; #if (!defined(NTL_LONGLONG_SP_MULMOD)) inline unsigned long PrepMulModPrecon(long b, long n, wide_double ninv) { long q = (long) ( (((wide_double) b) * wide_double(NTL_SP_BOUND)) * ninv ); unsigned long rr = (cast_unsigned(b) << NTL_SP_NBITS) - cast_unsigned(q)*cast_unsigned(n); q += sp_SignMask(rr) + sp_SignMask(rr-n) + 1L; return cast_unsigned(q) << (NTL_BITS_PER_LONG - NTL_SP_NBITS); } #else inline unsigned long sp_NormalizedPrepMulModPrecon(long b, long n, unsigned long ninv) { unsigned long H = cast_unsigned(b) << 2; unsigned long Q = ll_mul_hi(H, ninv); Q = Q >> NTL_POST_SHIFT; unsigned long L = cast_unsigned(b) << NTL_SP_NBITS; long r = L - Q*cast_unsigned(n); // r in [0..2*n) Q += 1L + sp_SignMask(r-n); return Q; // NOTE: not shifted } inline unsigned long PrepMulModPrecon(long b, long n, sp_inverse ninv) { return sp_NormalizedPrepMulModPrecon(b << ninv.shamt, n << ninv.shamt, ninv.inv) << (NTL_BITS_PER_LONG-NTL_SP_NBITS); } #endif inline long MulModPrecon(long a, long b, long n, unsigned long bninv) { unsigned long qq = ll_mul_hi(a, bninv); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - qq*cast_unsigned(n); return sp_CorrectExcess(long(rr), n); } inline long MulModPreconWithQuo(long& qres, long a, long b, long n, unsigned long bninv) { unsigned long qq = ll_mul_hi(a, bninv); unsigned long rr = cast_unsigned(a)*cast_unsigned(b) - qq*cast_unsigned(n); long r = sp_CorrectExcessQuo(qq, long(rr), n); qres = long(qq); return r; } #else // default, wide_double version typedef wide_double mulmod_precon_t; inline wide_double PrepMulModPrecon(long b, long n, wide_double ninv) { return ((wide_double) b) * ninv; } inline long MulModPrecon(long a, long b, long n, wide_double bninv) { return MulMod2_legacy(a, b, n, bninv); } inline long MulModPreconWithQuo(long& qq, long a, long b, long n, wide_double bninv) { return MulDivRem(qq, a, b, n, bninv); } #endif #if (defined(NTL_LONGLONG_SP_MULMOD)) // some annoying backward-compatibiliy nonsense struct sp_muldivrem_struct { unsigned long bninv; explicit sp_muldivrem_struct(unsigned long _bninv) : bninv(_bninv) { } sp_muldivrem_struct() NTL_DEFAULT }; typedef sp_muldivrem_struct muldivrem_t; inline sp_muldivrem_struct PrepMulDivRem(long b, long n, sp_inverse ninv) { return sp_muldivrem_struct(PrepMulModPrecon(b, n, ninv)); } inline long MulDivRem(long& qres, long a, long b, long n, sp_muldivrem_struct bninv) { return MulModPreconWithQuo(qres, a, b, n, bninv.bninv); } #endif inline mulmod_precon_t PrepMulModPrecon(long b, long n) { return PrepMulModPrecon(b, n, PrepMulMod(n)); } inline long MulMod(long a, long b, long n) { return MulMod(a, b, n, PrepMulMod(n)); } inline muldivrem_t PrepMulDivRem(long b, long n) { return PrepMulDivRem(b, n, PrepMulMod(n)); } #ifdef NTL_LEGACY_SP_MULMOD inline long MulMod2(long a, long b, long n, wide_double bninv) { return MulMod2_legacy(a, b, n, bninv); } #endif inline void VectorMulModPrecon(long k, long *x, const long *a, long b, long n, mulmod_precon_t bninv) { for (long i = 0; i < k; i++) x[i] = MulModPrecon(a[i], b, n, bninv); } inline void VectorMulMod(long k, long *x, const long *a, long b, long n, mulmod_t ninv) { mulmod_precon_t bninv; bninv = PrepMulModPrecon(b, n, ninv); VectorMulModPrecon(k, x, a, b, n, bninv); } inline void VectorMulMod(long k, long *x, const long *a, long b, long n) { mulmod_t ninv = PrepMulMod(n); VectorMulMod(k, x, a, b, n, ninv); } #ifdef NTL_HAVE_LL_TYPE struct sp_reduce_struct { unsigned long ninv; long sgn; sp_reduce_struct(unsigned long _ninv, long _sgn) : ninv(_ninv), sgn(_sgn) { } sp_reduce_struct() NTL_DEFAULT }; inline sp_reduce_struct sp_PrepRem(long n) { unsigned long q = (1UL << (NTL_BITS_PER_LONG-1))/cast_unsigned(n); long r = (1UL << (NTL_BITS_PER_LONG-1)) - q*cast_unsigned(n); long r1 = 2*r; q = 2*q; r1 = sp_CorrectExcessQuo(q, r1, n); return sp_reduce_struct(q, r); } inline long rem(unsigned long a, long n, sp_reduce_struct red) { unsigned long Q = ll_mul_hi(a, red.ninv); long r = a - Q*cast_unsigned(n); r = sp_CorrectExcess(r, n); return r; } inline long rem(long a, long n, sp_reduce_struct red) { unsigned long a0 = cast_unsigned(a) & ((1UL << (NTL_BITS_PER_LONG-1))-1); long r = rem(a0, n, red); long s = sp_SignMask(a) & red.sgn; return SubMod(r, s, n); } #else struct sp_reduce_struct { }; inline sp_reduce_struct sp_PrepRem(long n) { return sp_reduce_struct(); } inline long rem(unsigned long a, long n, sp_reduce_struct red) { return a % cast_unsigned(n); } inline long rem(long a, long n, sp_reduce_struct red) { long r = a % n; return sp_CorrectDeficit(r, n); } #endif #ifdef NTL_HAVE_LL_TYPE #define NTL_HAVE_SP_LL_ROUTINES // some routines that are currently not part of the documented // interface. They currently are only defined when we have appropriate // LL type. struct sp_ll_reduce_struct { unsigned long inv; long nbits; sp_ll_reduce_struct() NTL_DEFAULT sp_ll_reduce_struct(unsigned long _inv, long _nbits) : inv(_inv), nbits(_nbits) { } }; inline sp_ll_reduce_struct make_sp_ll_reduce_struct(long n) { long nbits = NTL_BITS_PER_LONG - sp_CountLeadingZeros(n); unsigned long inv = (unsigned long) ( ((((NTL_ULL_TYPE) 1) << (nbits+NTL_BITS_PER_LONG))-1UL) / ((NTL_ULL_TYPE) n) ); return sp_ll_reduce_struct(inv, nbits); } // computes remainder (hi, lo) mod d, assumes hi < d inline long sp_ll_red_21(unsigned long hi, unsigned long lo, long d, sp_ll_reduce_struct dinv) { unsigned long H = (hi << (NTL_BITS_PER_LONG-dinv.nbits)) | (lo >> dinv.nbits); unsigned long Q = ll_mul_hi(H, dinv.inv) + H; unsigned long rr = lo - Q*cast_unsigned(d); // rr in [0..4*d) long r = sp_CorrectExcess(rr, 2*d); // r in [0..2*d) r = sp_CorrectExcess(r, d); return r; } // computes remainder (x[n-1], ..., x[0]) mod d inline long sp_ll_red_n1(const unsigned long *x, long n, long d, sp_ll_reduce_struct dinv) { long carry = 0; long i; for (i = n-1; i >= 0; i--) carry = sp_ll_red_21(carry, x[i], d, dinv); return carry; } // computes remainder (x2, x1, x0) mod d, assumes x2 < d inline long sp_ll_red_31(unsigned long x2, unsigned long x1, unsigned long x0, long d, sp_ll_reduce_struct dinv) { long carry = sp_ll_red_21(x2, x1, d, dinv); return sp_ll_red_21(carry, x0, d, dinv); } // normalized versions of the above: assume NumBits(d) == NTL_SP_NBITS // computes remainder (hi, lo) mod d, assumes hi < d inline long sp_ll_red_21_normalized(unsigned long hi, unsigned long lo, long d, sp_ll_reduce_struct dinv) { unsigned long H = (hi << (NTL_BITS_PER_LONG-NTL_SP_NBITS)) | (lo >> NTL_SP_NBITS); unsigned long Q = ll_mul_hi(H, dinv.inv) + H; unsigned long rr = lo - Q*cast_unsigned(d); // rr in [0..4*d) long r = sp_CorrectExcess(rr, 2*d); // r in [0..2*d) r = sp_CorrectExcess(r, d); return r; } // computes remainder (x[n-1], ..., x[0]) mod d inline long sp_ll_red_n1_normalized(const unsigned long *x, long n, long d, sp_ll_reduce_struct dinv) { long carry = 0; long i; for (i = n-1; i >= 0; i--) carry = sp_ll_red_21_normalized(carry, x[i], d, dinv); return carry; } // computes remainder (x2, x1, x0) mod d, assumes x2 < d inline long sp_ll_red_31_normalized(unsigned long x2, unsigned long x1, unsigned long x0, long d, sp_ll_reduce_struct dinv) { long carry = sp_ll_red_21_normalized(x2, x1, d, dinv); return sp_ll_red_21_normalized(carry, x0, d, dinv); } #else // provided to streamline some code struct sp_ll_reduce_struct { }; inline sp_ll_reduce_struct make_sp_ll_reduce_struct(long n) { return sp_ll_reduce_struct(); } #endif NTL_CLOSE_NNS #endif /************************************************************************** Implementation notes -- the LONGLONG MulMod implementation I started out basing this on Granlund-Moeller multiplication, but it evolved into something a little bit different. We assume that modulus n has w bits, so 2^{w-1} <= n < 2^w. We also assume that 2 <= w <= BPL-2. As a precomputation step, we compute X = floor((2^v-1)/n), i.e., 2^v - 1 = X n + Y, where 0 <= Y < n Now, we are given U to reduce mod n. Write U = H 2^s + L H X = Q 2^t + R where s + t = v. Some simple calculations yield: H <= U/2^s 2^{v-w} <= X < 2^v/n <= 2^{v-w+1} H X < 2^t U / n Also: U - Qn < n U / 2^v + L + n For the case where BPL >= 64, we generally work with w = BPL-4. In this case, we set v = 2w+2, s = w-2, t = w+4. Then we have: U - Qn < n/4 + n/2 + n < 2n This choice of parameters allows us to do a MulMod with just a single correction. It also allows us to do the LazyPrepMulModPrecon step with just a single correction. If w = BPL-2, we set v = 2w+1, s = w-2, t = w+3. Then we have: U - Qn < n/2 + n/2 + n = 2n So again, we we do a MulMod with just a single correction, although the LazyPrepMulModPrecon now takes two corrections. For the Lazy stuff, we are computing floor(2^{w+2}b/n), so U = 2^{w+2} b. For the case w = BPL-4, we are setting s = w+2 and t = w. L = 0 in this case, and we obtain U - Qn < n + n = 2n. In the case w = BPL-2, we set s = w, t = w+1. We obtain U - Qn < 2n + n = 3n. Also, we need to write X = 2^{w+1} + X_0 to perform the HX computation correctly. ***************************************************************************/ ntl-11.5.1/include/NTL/ZZVec.h0000644417616742025610000000350614064716022017413 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_ZZVec__H #define NTL_ZZVec__H #include NTL_OPEN_NNS /***************************************************************** The class ZZVec implements vectors of fixed-length ZZ's. You can allocate a vector of ZZ's of a specified length, where the maximum size of each ZZ is also specified. These parameters can be specified once, either with a constructor, or with SetSize. It is an error to try to re-size a vector, or store a ZZ that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_ZZ. *****************************************************************/ class ZZVec { private: ZZ* v; long len; long bsize; public: ZZVec& operator=(const ZZVec&); ZZVec(const ZZVec&); long length() const { return len; } long BaseSize() const { return bsize; } void SetSize(long n, long d); void kill(); ZZVec() : v(0), len(0), bsize(0) { } ZZVec(long n, long d) : v(0), len(0), bsize(0) { SetSize(n, d); } ~ZZVec() { kill(); }; ZZ* elts() { return v; } const ZZ* elts() const { return v; } ZZ& operator[](long i) { return v[i]; } const ZZ& operator[](long i) const { return v[i]; } void swap(ZZVec& x) { _ntl_swap(v, x.v); _ntl_swap(len, x.len); _ntl_swap(bsize, x.bsize); } void move(ZZVec& other) { ZZVec tmp; tmp.swap(other); tmp.swap(*this); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) ZZVec(ZZVec&& other) noexcept : ZZVec() { this->move(other); } ZZVec& operator=(ZZVec&& other) noexcept { this->move(other); return *this; } #endif }; NTL_DECLARE_RELOCATABLE((ZZVec*)) inline void swap(ZZVec& x, ZZVec& y) { x.swap(y); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZX.h0000644417616742025610000004663314064716022017115 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZX__H #define NTL_ZZX__H #include #include #include NTL_OPEN_NNS class ZZX { public: vec_ZZ rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZX() { } // initial value 0 explicit ZZX(long a) { *this = a; } explicit ZZX(const ZZ& a) { *this = a; } ZZX(INIT_SIZE_TYPE, long n) // initial value 0, but space is pre-allocated for n coefficients { rep.SetMaxLength(n); } // default copy constructor and assignment // default destructor void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } typedef ZZ coeff_type; void SetLength(long n) { rep.SetLength(n); } ZZ& operator[](long i) { return rep[i]; } const ZZ& operator[](long i) const { return rep[i]; } static const ZZX& zero(); inline ZZX(long i, const ZZ& c); inline ZZX(long i, long c); inline ZZX(INIT_MONO_TYPE, long i, const ZZ& c); inline ZZX(INIT_MONO_TYPE, long i, long c); inline ZZX(INIT_MONO_TYPE, long i); inline ZZX& operator=(long a); inline ZZX& operator=(const ZZ& a); ZZX(ZZX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } void swap(ZZX& x) { rep.swap(x.rep); } // swap with x (only pointers are swapped) }; NTL_DECLARE_RELOCATABLE((ZZX*)) /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). Leading zeroes are stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ& coeff(const ZZX& a, long i); // zero if i not in range void GetCoeff(ZZ& x, const ZZX& a, long i); // x = a[i], or zero if i not in range const ZZ& LeadCoeff(const ZZX& a); // zero if a == 0 const ZZ& ConstTerm(const ZZX& a); // zero if a == 0 void SetCoeff(ZZX& x, long i, const ZZ& a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZX::ZZX(long i, const ZZ& a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(long i, long a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i, const ZZ& a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZX::ZZX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZX& x); // x is set to the monomial X long IsX(const ZZX& a); // test if x = X inline void clear(ZZX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZX& x, ZZX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m inline ZZX trunc(const ZZX& a, long m) { ZZX x; trunc(x, a, m); NTL_OPT_RETURN(ZZX, x); } void RightShift(ZZX& x, const ZZX& a, long n); // x = a/X^n inline ZZX RightShift(const ZZX& a, long n) { ZZX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } void LeftShift(ZZX& x, const ZZX& a, long n); // x = a*X^n inline ZZX LeftShift(const ZZX& a, long n) { ZZX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } #ifndef NTL_TRANSITION inline ZZX operator>>(const ZZX& a, long n) { ZZX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator<<(const ZZX& a, long n) { ZZX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator<<=(ZZX& x, long n) { LeftShift(x, x, n); return x; } inline ZZX& operator>>=(ZZX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZX& x, const ZZX& a); // x = derivative of a inline ZZX diff(const ZZX& a) { ZZX x; diff(x, a); NTL_OPT_RETURN(ZZX, x); } void InvTrunc(ZZX& x, const ZZX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline ZZX InvTrunc(const ZZX& a, long m) { ZZX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZX, x); } void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n); // x = a * b % X^n inline ZZX MulTrunc(const ZZX& a, const ZZX& b, long n) { ZZX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZX, x); } void SqrTrunc(ZZX& x, const ZZX& a, long n); // x = a^2 % X^n inline ZZX SqrTrunc(const ZZX& a, long n) { ZZX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZX, x); } void reverse(ZZX& c, const ZZX& a, long hi); inline ZZX reverse(const ZZX& a, long hi) { ZZX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZX, x); } inline void reverse(ZZX& c, const ZZX& a) { reverse(c, a, deg(a)); } inline ZZX reverse(const ZZX& a) { ZZX x; reverse(x, a); NTL_OPT_RETURN(ZZX, x); } inline void VectorCopy(vec_ZZ& x, const ZZX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ VectorCopy(const ZZX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZX& x, long a); inline ZZX to_ZZX(long a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& ZZX::operator=(long a) { conv(*this, a); return *this; } void conv(ZZX& x, const ZZ& a); inline ZZX to_ZZX(const ZZ& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& ZZX::operator=(const ZZ& a) { conv(*this, a); return *this; } void conv(ZZX& x, const vec_ZZ& a); inline ZZX to_ZZX(const vec_ZZ& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } void conv(zz_pX& x, const ZZX& a); inline zz_pX to_zz_pX(const ZZX& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(ZZ_pX& x, const ZZX& a); inline ZZ_pX to_ZZ_pX(const ZZX& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void conv(ZZX& x, const ZZ_pX& a); inline ZZX to_ZZX(const ZZ_pX& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } void conv(ZZX& x, const zz_pX& a); inline ZZX to_ZZX(const zz_pX& a) { ZZX x; conv(x, a); NTL_OPT_RETURN(ZZX, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZX& x, const ZZX& a) { x = a; } inline void conv(vec_ZZ& x, const ZZX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZX& a); long IsOne(const ZZX& a); long operator==(const ZZX& a, const ZZX& b); inline long operator!=(const ZZX& a, const ZZX& b) { return !(a == b); } long operator==(const ZZX& a, const ZZ& b); long operator==(const ZZX& a, long b); inline long operator==(const ZZ& a, const ZZX& b) { return b == a; } inline long operator==(long a, const ZZX& b) { return b == a; } inline long operator!=(const ZZX& a, const ZZ& b) { return !(a == b); } inline long operator!=(const ZZX& a, long b) { return !(a == b); } inline long operator!=(const ZZ& a, const ZZX& b) { return !(a == b); } inline long operator!=(long a, const ZZX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b void negate(ZZX& x, const ZZX& a); // x = -a // scalar versions void add(ZZX & x, const ZZX& a, const ZZ& b); // x = a + b void add(ZZX& x, const ZZX& a, long b); inline void add(ZZX& x, const ZZ& a, const ZZX& b) { add(x, b, a); } inline void add(ZZX& x, long a, const ZZX& b) { add(x, b, a); } void sub(ZZX & x, const ZZX& a, const ZZ& b); // x = a - b void sub(ZZX& x, const ZZX& a, long b); void sub(ZZX& x, const ZZ& a, const ZZX& b); void sub(ZZX& x, long a, const ZZX& b); inline ZZX operator+(const ZZX& a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZX& a, const ZZ& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZX& a, long b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(const ZZ& a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator+(long a, const ZZX& b) { ZZX x; add(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, const ZZ& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZX& a, long b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(const ZZ& a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator-(long a, const ZZX& b) { ZZX x; sub(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator+=(ZZX& x, const ZZX& b) { add(x, x, b); return x; } inline ZZX& operator+=(ZZX& x, const ZZ& b) { add(x, x, b); return x; } inline ZZX& operator+=(ZZX& x, long b) { add(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, const ZZX& b) { sub(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, const ZZ& b) { sub(x, x, b); return x; } inline ZZX& operator-=(ZZX& x, long b) { sub(x, x, b); return x; } inline ZZX operator-(const ZZX& a) { ZZX x; negate(x, a); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator++(ZZX& x) { add(x, x, 1); return x; } inline void operator++(ZZX& x, int) { add(x, x, 1); } inline ZZX& operator--(ZZX& x) { sub(x, x, 1); return x; } inline void operator--(ZZX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b void sqr(ZZX& x, const ZZX& a); inline ZZX sqr(const ZZX& a) { ZZX x; sqr(x, a); NTL_OPT_RETURN(ZZX, x); } // x = a^2 void PlainMul(ZZX& x, const ZZX& a, const ZZX& b); void PlainSqr(ZZX& x, const ZZX& a); void KarMul(ZZX& x, const ZZX& a, const ZZX& b); void KarSqr(ZZX& x, const ZZX& a); void HomMul(ZZX& x, const ZZX& a, const ZZX& b); void HomSqr(ZZX& x, const ZZX& a); void SSMul(ZZX& x, const ZZX& a, const ZZX& b); void SSSqr(ZZX& x, const ZZX& a); void SSMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); void SSSqr(ZZ_pX& x, const ZZ_pX& a); void KarMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); void KarSqr(ZZ_pX& x, const ZZ_pX& a); double SSRatio(long na, long maxa, long nb, long maxb); void mul(ZZX & x, const ZZX& a, const ZZ& b); void mul(ZZX& x, const ZZX& a, long b); inline void mul(ZZX& x, const ZZ& a, const ZZX& b) { mul(x, b, a); } inline void mul(ZZX& x, long a, const ZZX& b) { mul(x, b, a); } inline ZZX operator*(const ZZX& a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZX& a, const ZZ& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZX& a, long b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(const ZZ& a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator*(long a, const ZZX& b) { ZZX x; mul(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator*=(ZZX& x, const ZZX& b) { mul(x, x, b); return x; } inline ZZX& operator*=(ZZX& x, const ZZ& b) { mul(x, x, b); return x; } inline ZZX& operator*=(ZZX& x, long b) { mul(x, x, b); return x; } /************************************************************* Division **************************************************************/ // "plain" versions void PlainPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void PlainPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); void PlainPseudoRem(ZZX& r, const ZZX& a, const ZZX& b); // "homomorphic imaging" versions void HomPseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void HomPseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); void HomPseudoRem(ZZX& r, const ZZX& a, const ZZX& b); inline void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b) // performs pseudo-division: computes q and r // with deg(r) < deg(b), and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r. // current implementation always defaults to "plain" { PlainPseudoDivRem(q, r, a, b); } inline void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b) { PlainPseudoDiv(q, a, b); } inline void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b) { PlainPseudoRem(r, a, b); } inline ZZX PseudoDiv(const ZZX& a, const ZZX& b) { ZZX x; PseudoDiv(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX PseudoRem(const ZZX& a, const ZZX& b) { ZZX x; PseudoRem(x, a, b); NTL_OPT_RETURN(ZZX, x); } #ifndef NTL_TRANSITION void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZ& b); void div(ZZX& q, const ZZX& a, long b); void rem(ZZX& r, const ZZX& a, const ZZX& b); inline ZZX operator/(const ZZX& a, const ZZX& b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator/(const ZZX& a, const ZZ& b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX operator/(const ZZX& a, long b) { ZZX x; div(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator/=(ZZX& x, const ZZ& b) { div(x, x, b); return x; } inline ZZX& operator/=(ZZX& x, long b) { div(x, x, b); return x; } inline ZZX& operator/=(ZZX& x, const ZZX& b) { div(x, x, b); return x; } inline ZZX operator%(const ZZX& a, const ZZX& b) { ZZX x; rem(x, a, b); NTL_OPT_RETURN(ZZX, x); } inline ZZX& operator%=(ZZX& x, const ZZX& b) { rem(x, x, b); return x; } #endif // Modular arithemtic---f must be monic, and other args // must have degree less than that of f void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f); inline ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f) { ZZX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZX, x); } void SqrMod(ZZX& x, const ZZX& a, const ZZX& f); inline ZZX SqrMod(const ZZX& a, const ZZX& f) { ZZX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f); inline ZZX MulByXMod(const ZZX& a, const ZZX& f) { ZZX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } // these always use "plain" division long PlainDivide(ZZX& q, const ZZX& a, const ZZX& b); long PlainDivide(const ZZX& a, const ZZX& b); // these always use "homomorphic imaging" long HomDivide(ZZX& q, const ZZX& a, const ZZX& b); long HomDivide(const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZ& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZ& b); // if b | a, returns 1; otherwise returns 0 //single-precision versions long divide(ZZX& q, const ZZX& a, long b); long divide(const ZZX& a, long b); void content(ZZ& d, const ZZX& f); // d = content of f, sign(d) == sign(LeadCoeff(f)) inline ZZ content(const ZZX& f) { ZZ x; content(x, f); NTL_OPT_RETURN(ZZ, x); } void PrimitivePart(ZZX& pp, const ZZX& f); // pp = primitive part of f, LeadCoeff(pp) >= 0 inline ZZX PrimitivePart(const ZZX& f) { ZZX x; PrimitivePart(x, f); NTL_OPT_RETURN(ZZX, x); } void GCD(ZZX& d, const ZZX& a, const ZZX& b); // d = gcd(a, b), LeadCoeff(d) >= 0 inline ZZX GCD(const ZZX& a, const ZZX& b) { ZZX x; GCD(x, a, b); NTL_OPT_RETURN(ZZX, x); } long MaxBits(const ZZX& f); // returns max NumBits of coefficients of f long CharPolyBound(const ZZX& a, const ZZX& f); /*************************************************************** traces, norms, resultants ****************************************************************/ void TraceVec(vec_ZZ& S, const ZZX& f); // S[i] = Trace(X^i mod f), for i = 0..deg(f)-1. // f must be a monic polynomial. inline vec_ZZ TraceVec(const ZZX& f) { vec_ZZ x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ, x); } void TraceMod(ZZ& res, const ZZX& a, const ZZX& f); inline ZZ TraceMod(const ZZX& a, const ZZX& f) { ZZ x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ, x); } // res = trace of (a mod f) // f must be monic void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0); inline ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0) { ZZ x; resultant(x, a, b, deterministic); NTL_OPT_RETURN(ZZ, x); } // res = resultant of a and b // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0); inline ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0) { ZZ x; NormMod(x, a, f, deterministic); NTL_OPT_RETURN(ZZ, x); } // res = norm of (a mod f) // f must be monic // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void discriminant(ZZ& d, const ZZX& a, long deterministic=0); inline ZZ discriminant(const ZZX& a, long deterministic=0) { ZZ x; discriminant(x, a, deterministic); NTL_OPT_RETURN(ZZ, x); } // d = discriminant of a // = (-1)^{m(m-1)/2} resultant(a, a')/lc(a), // where m = deg(a) // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0); inline ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0) { ZZX x; CharPolyMod(x, a, f, deterministic); NTL_OPT_RETURN(ZZX, x); } // g = char poly of (a mod f) // f must be monic // if !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f); inline ZZX MinPolyMod(const ZZX& a, const ZZX& f) { ZZX x; MinPolyMod(x, a, f); NTL_OPT_RETURN(ZZX, x); } // g = min poly of (a mod f) // f must be monic // may use a probabilistic strategy that errs with // probability no more than 2^{-80} void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b, long deterministic=0); // r = resultant of a and b; // if r != 0, then computes s and t such that: // a*s + b*t = r; // otherwise s and t not affected. // if !deterministic, then resultant computation may use a randomized strategy // that errs with probability no more than 2^{-80}. /****************************************************** Incremental Chinese Remaindering *******************************************************/ long CRT(ZZX& a, ZZ& prod, const zz_pX& A); long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A); // If p is the current modulus with (p, prod) = 1; // Computes b such that b = a mod prod and b = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a = b, prod = p*prod, and returns 1 if a's value changed. typedef Vec vec_ZZX; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZXFactoring.h0000644417616742025610000000344214064716022020741 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_ZZXFactoring__H #define NTL_ZZXFactoring__H #include #include NTL_OPEN_NNS void mul(ZZX& x, const vec_pair_ZZX_long& a); inline ZZX mul(const vec_pair_ZZX_long& v) { ZZX x; mul(x, v); return x; } void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f); inline vec_pair_ZZX_long SquareFreeDecomp(const ZZX& f) { vec_pair_ZZX_long x; SquareFreeDecomp(x, f); return x; } // input is primitive, with positive leading coefficient void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose=0); // Using current value p of zz_p::modulus(), this lifts // the square-free factorization a mod p of f to a factorization // A mod p^e of f. // It is required that f and all the polynomials in a are monic. void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0); inline vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0) { vec_ZZX x; SFFactor(x, f, verbose, bnd); return x; } // input f is primitive and square-free, with positive leading // coefficient. // bnd, if not zero, indicates that // f divides a polynomial h whose Euclidean norm // is bounded by 2^{bnd} in absolute value. extern NTL_CHEAP_THREAD_LOCAL long ZZXFac_MaxPrune; extern NTL_CHEAP_THREAD_LOCAL long ZZXFac_InitNumPrimes; extern NTL_CHEAP_THREAD_LOCAL long ZZXFac_MaxNumPrimes; extern NTL_CHEAP_THREAD_LOCAL long ZZXFac_PowerHack; extern NTL_CHEAP_THREAD_LOCAL long ZZXFac_van_Hoeij; void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose=0, long bnd=0); // input f is is an arbitrary polynomial. // c is the content of f, and factors is the factorization // of its primitive part. // bnd is as in SFFactor. NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_p.h0000644417616742025610000003127114064716022017274 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_p__H #define NTL_ZZ_p__H #include #include #include #include NTL_OPEN_NNS // ZZ_p representation: each ZZ_p is represented by a ZZ in the range 0..p-1. class ZZ_pFFTInfoT { private: ZZ_pFFTInfoT(const ZZ_pFFTInfoT&); // disabled void operator=(const ZZ_pFFTInfoT&); // disabled public: ZZ_pFFTInfoT() { } long NumPrimes; long MaxRoot; ZZ MinusMModP; // -M mod p, M = product of primes ZZ_CRTStructAdapter crt_struct; ZZ_RemStructAdapter rem_struct; // the following arrays are indexed 0..NumPrimes-1 // q[i] = FFTPrime[i] Vec prime; // prime[i] = q[i] Vec prime_recip; // prime_recip[i] = 1/double(q[i]) Vec u; // u[i] = (M/q[i])^{-1} mod q[i] Vec uqinv; ZZ_ReduceStructAdapter reduce_struct; }; #ifndef NTL_WIZARD_HACK struct MatPrime_crt_helper; void MatPrime_crt_helper_deleter(MatPrime_crt_helper*); #endif class ZZ_pInfoT { private: ZZ_pInfoT(); // disabled ZZ_pInfoT(const ZZ_pInfoT&); // disabled void operator=(const ZZ_pInfoT&); // disabled public: ZZ_pInfoT(const ZZ& NewP); ZZ p; // the modulus long size; // p.size() long ExtendedModulusSize; Lazy FFTInfo; #ifndef NTL_WIZARD_HACK struct MatPrime_crt_helper_deleter_policy { static void deleter(MatPrime_crt_helper *p) { MatPrime_crt_helper_deleter(p); } }; Lazy MatPrime_crt_helper_info; // PIMPL #endif }; // auxilliary data structures to store space for temporaries // used by the crt and rem routines in the low-level lip module. // These used to be stored in data structures managed by the // lip module, but to achieve thread-safety, they have to be // externally on a per-thread basis. class ZZ_pTmpSpaceT { public: ZZ_TmpVecAdapter crt_tmp_vec; ZZ_TmpVecAdapter rem_tmp_vec; }; extern NTL_CHEAP_THREAD_LOCAL ZZ_pInfoT *ZZ_pInfo; // info for current modulus, initially null // plain pointer for faster TLS access extern NTL_CHEAP_THREAD_LOCAL ZZ_pTmpSpaceT *ZZ_pTmpSpace; // space for temps associated with current modulus, // plain pointer for faster TLS access extern NTL_CHEAP_THREAD_LOCAL bool ZZ_pInstalled; // flag indicating if current modulus is fully installed class ZZ_pContext { private: SmartPtr ptr; public: ZZ_pContext() { } explicit ZZ_pContext(const ZZ& p) : ptr(MakeSmart(p)) { } // copy constructor, assignment, destructor: default void save(); void restore() const; }; class ZZ_pBak { private: ZZ_pContext c; bool MustRestore; ZZ_pBak(const ZZ_pBak&); // disabled void operator=(const ZZ_pBak&); // disabled public: void save(); void restore(); ZZ_pBak() : MustRestore(false) { } ~ZZ_pBak(); }; class ZZ_pPush { private: ZZ_pBak bak; ZZ_pPush(const ZZ_pPush&); // disabled void operator=(const ZZ_pPush&); // disabled public: ZZ_pPush() { bak.save(); } explicit ZZ_pPush(const ZZ_pContext& context) { bak.save(); context.restore(); } explicit ZZ_pPush(const ZZ& p) { bak.save(); ZZ_pContext c(p); c.restore(); } }; class ZZ_pX; // forward declaration class ZZ_p { public: typedef ZZ rep_type; typedef ZZ_pContext context_type; typedef ZZ_pBak bak_type; typedef ZZ_pPush push_type; typedef ZZ_pX poly_type; ZZ _ZZ_p__rep; static void init(const ZZ&); typedef void (*DivHandlerPtr)(const ZZ_p& a); // error-handler for division static NTL_CHEAP_THREAD_LOCAL DivHandlerPtr DivHandler; // ****** constructors and assignment ZZ_p() { } // NO_ALLOC explicit ZZ_p(long a) { *this = a; } ZZ_p(INIT_NO_ALLOC_TYPE) { } // allocates no space ZZ_p(INIT_ALLOC_TYPE) { _ZZ_p__rep.SetSize(ZZ_pInfo->size); } // allocates space inline ZZ_p& operator=(long a); // You can always access the _ZZ_p__representation directly...if you dare. ZZ& LoopHole() { return _ZZ_p__rep; } ZZ_p(ZZ_p& x, INIT_TRANS_TYPE) : _ZZ_p__rep(x._ZZ_p__rep, INIT_TRANS) { } static const ZZ& modulus() { return ZZ_pInfo->p; } static long ModulusSize() { return ZZ_pInfo->size; } static long storage() { return ZZ_storage(ZZ_pInfo->size); } static long ExtendedModulusSize() { return ZZ_pInfo->ExtendedModulusSize; } static const ZZ_p& zero(); static void DoInstall(); static void install() { // we test and set ZZ_pInstalled here, to allow better // inlining and optimization if (!ZZ_pInstalled) { DoInstall(); ZZ_pInstalled = true; } } static const ZZ_pFFTInfoT* GetFFTInfo() { install(); return ZZ_pInfo->FFTInfo.get(); } static ZZ_pTmpSpaceT* GetTmpSpace() { install(); return ZZ_pTmpSpace; } ZZ_p(INIT_VAL_TYPE, const ZZ& a); ZZ_p(INIT_VAL_TYPE, long a); void swap(ZZ_p& x) { _ZZ_p__rep.swap(x._ZZ_p__rep); } void allocate() { long sz = ZZ_pInfo->size; if (_ZZ_p__rep.MaxAlloc() < sz) _ZZ_p__rep.SetSize(sz); } // mainly for internal consumption by the ZZ_pWatcher class below void KillBig() { _ZZ_p__rep.KillBig(); } }; NTL_DECLARE_RELOCATABLE((ZZ_p*)) // read-only access to _ZZ_p__representation inline const ZZ& rep(const ZZ_p& a) { return a._ZZ_p__rep; } // ****** conversion inline void conv(ZZ_p& x, const ZZ& a) { rem(x._ZZ_p__rep, a, ZZ_p::modulus()); } inline ZZ_p to_ZZ_p(const ZZ& a) { return ZZ_p(INIT_VAL, a); } void conv(ZZ_p& x, long a); inline ZZ_p to_ZZ_p(long a) { return ZZ_p(INIT_VAL, a); } // ****** some basics inline void clear(ZZ_p& x) // x = 0 { clear(x._ZZ_p__rep); } inline void set(ZZ_p& x) // x = 1 { set(x._ZZ_p__rep); } inline void swap(ZZ_p& x, ZZ_p& y) // swap x and y { x.swap(y); } // ****** addition inline void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a + b { AddMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a - b { SubMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void negate(ZZ_p& x, const ZZ_p& a) // x = -a { NegateMod(x._ZZ_p__rep, a._ZZ_p__rep, ZZ_p::modulus()); } // scalar versions void add(ZZ_p& x, const ZZ_p& a, long b); inline void add(ZZ_p& x, long a, const ZZ_p& b) { add(x, b, a); } void sub(ZZ_p& x, const ZZ_p& a, long b); void sub(ZZ_p& x, long a, const ZZ_p& b); // ****** multiplication inline void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b) // x = a*b { MulMod(x._ZZ_p__rep, a._ZZ_p__rep, b._ZZ_p__rep, ZZ_p::modulus()); } inline void sqr(ZZ_p& x, const ZZ_p& a) // x = a^2 { SqrMod(x._ZZ_p__rep, a._ZZ_p__rep, ZZ_p::modulus()); } inline ZZ_p sqr(const ZZ_p& a) { ZZ_p x; sqr(x, a); NTL_OPT_RETURN(ZZ_p, x); } // scalar versions void mul(ZZ_p& x, const ZZ_p& a, long b); inline void mul(ZZ_p& x, long a, const ZZ_p& b) { mul(x, b, a); } // ****** division void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a/b // If b != 0 & b not invertible & DivHandler != 0, // then DivHandler will be called with the offending b. // In this case, of course, p is not really prime, and one // can factor p by taking a gcd with rep(b). // Otherwise, if b is not invertible, an error occurs. void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a // Error handling is the same as above. inline ZZ_p inv(const ZZ_p& a) { ZZ_p x; inv(x, a); NTL_OPT_RETURN(ZZ_p, x); } void div(ZZ_p& x, const ZZ_p& a, long b); void div(ZZ_p& x, long a, const ZZ_p& b); // operator notation: inline ZZ_p operator+(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator+(const ZZ_p& a, long b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator+(long a, const ZZ_p& b) { ZZ_p x; add(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_p& operator+=(ZZ_p& x, long b) { add(x, x, b); return x; } inline ZZ_p operator-(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator-(const ZZ_p& a, long b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator-(long a, const ZZ_p& b) { ZZ_p x; sub(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_p& operator-=(ZZ_p& x, long b) { sub(x, x, b); return x; } inline ZZ_p operator*(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator*(const ZZ_p& a, long b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator*(long a, const ZZ_p& b) { ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_p& operator*=(ZZ_p& x, long b) { mul(x, x, b); return x; } inline ZZ_p operator/(const ZZ_p& a, const ZZ_p& b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator/(const ZZ_p& a, long b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p operator/(long a, const ZZ_p& b) { ZZ_p x; div(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_p& operator/=(ZZ_p& x, long b) { div(x, x, b); return x; } inline ZZ_p operator-(const ZZ_p& a) { ZZ_p x; negate(x, a); NTL_OPT_RETURN(ZZ_p, x); } inline ZZ_p& operator++(ZZ_p& x) { add(x, x, 1); return x; } inline void operator++(ZZ_p& x, int) { add(x, x, 1); } inline ZZ_p& operator--(ZZ_p& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_p& x, int) { sub(x, x, 1); } // ****** exponentiation inline void power(ZZ_p& x, const ZZ_p& a, const ZZ& e) { PowerMod(x._ZZ_p__rep, a._ZZ_p__rep, e, ZZ_p::modulus()); } inline ZZ_p power(const ZZ_p& a, const ZZ& e) { ZZ_p x; power(x, a, e); NTL_OPT_RETURN(ZZ_p, x); } inline void power(ZZ_p& x, const ZZ_p& a, long e) { PowerMod(x._ZZ_p__rep, a._ZZ_p__rep, e, ZZ_p::modulus()); } inline ZZ_p power(const ZZ_p& a, long e) { ZZ_p x; power(x, a, e); NTL_OPT_RETURN(ZZ_p, x); } // ****** comparison inline long IsZero(const ZZ_p& a) { return IsZero(a._ZZ_p__rep); } inline long IsOne(const ZZ_p& a) { return IsOne(a._ZZ_p__rep); } inline long operator==(const ZZ_p& a, const ZZ_p& b) { return a._ZZ_p__rep == b._ZZ_p__rep; } inline long operator!=(const ZZ_p& a, const ZZ_p& b) { return !(a == b); } long operator==(const ZZ_p& a, long b); inline long operator==(long a, const ZZ_p& b) { return b == a; } inline long operator!=(const ZZ_p& a, long b) { return !(a == b); } inline long operator!=(long a, const ZZ_p& b) { return !(a == b); } // ****** random numbers inline void random(ZZ_p& x) // x = random element in ZZ_p { RandomBnd(x._ZZ_p__rep, ZZ_p::modulus()); } inline ZZ_p random_ZZ_p() { ZZ_p x; random(x); NTL_OPT_RETURN(ZZ_p, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_p& a) { return s << a._ZZ_p__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_p& x); inline ZZ_p& ZZ_p::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(unsigned int& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(long& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(unsigned long& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(ZZ& x, const ZZ_p& a) { conv(x, rep(a)); } inline void conv(ZZ_p& x, const ZZ_p& a) { x = a; } /* ------------------------------------- */ // Thread-boosted conversion. Defined in vec_zz_p.cpp. void conv(Vec& x, const Vec& a); /* ------------------------------------- */ // overload these functions for Vec. // They are defined in vec_ZZ_p.c void BlockConstruct(ZZ_p* p, long n); void BlockConstructFromVec(ZZ_p* p, long n, const ZZ_p* q); void BlockConstructFromObj(ZZ_p* p, long n, const ZZ_p& q); void BlockDestroy(ZZ_p* p, long n); // ZZ_p scratch variables class ZZ_pWatcher { public: ZZ_p& watched; explicit ZZ_pWatcher(ZZ_p& _watched) : watched(_watched) { } ~ZZ_pWatcher() { watched.KillBig(); } }; #define NTL_ZZ_pRegister(x) NTL_TLS_LOCAL(ZZ_p, x); ZZ_pWatcher _WATCHER__ ## x(x); x.allocate() // FIXME: register variables that are allocated with respect to one modulus // and then reused with another modulus may have initial values that are // not in the correct range. This should not cause any problems, though, // as these register values should always be written to before being read. // Note also that the underlying integer reps may have space // allocated that is smaller or *bigger* than the current modulus. // This may impact future interface design changes --- especially // one that tries to make "out of context" copy constructors // safe by reading the allocated space of the source. NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_pE.h0000644417616742025610000003004314064716022017375 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_pE__H #define NTL_ZZ_pE__H #include #include #include #include NTL_OPEN_NNS class ZZ_pEInfoT { private: ZZ_pEInfoT(); // disabled ZZ_pEInfoT(const ZZ_pEInfoT&); // disabled void operator=(const ZZ_pEInfoT&); // disabled public: ZZ_pEInfoT(const ZZ_pX&); ZZ_pXModulus p; ZZ _card_base; long _card_exp; Lazy _card; }; extern NTL_CHEAP_THREAD_LOCAL ZZ_pEInfoT *ZZ_pEInfo; // info for current modulus, initially null // raw pointer for faster TLS access class ZZ_pEContext { private: SmartPtr ptr; public: ZZ_pEContext() { } explicit ZZ_pEContext(const ZZ_pX& p) : ptr(MakeSmart(p)) { } // copy constructor, assignment, destructor: default void save(); void restore() const; }; class ZZ_pEBak { private: ZZ_pEContext c; bool MustRestore; ZZ_pEBak(const ZZ_pEBak&); // disabled void operator=(const ZZ_pEBak&); // disabled public: void save(); void restore(); ZZ_pEBak() : MustRestore(false) { } ~ZZ_pEBak(); }; class ZZ_pEPush { private: ZZ_pEBak bak; ZZ_pEPush(const ZZ_pEPush&); // disabled void operator=(const ZZ_pEPush&); // disabled public: ZZ_pEPush() { bak.save(); } explicit ZZ_pEPush(const ZZ_pEContext& context) { bak.save(); context.restore(); } explicit ZZ_pEPush(const ZZ_pX& p) { bak.save(); ZZ_pEContext c(p); c.restore(); } }; class ZZ_pEX; // forward declaration class ZZ_pE { public: typedef ZZ_pX rep_type; typedef ZZ_pEContext context_type; typedef ZZ_pEBak bak_type; typedef ZZ_pEPush push_type; typedef ZZ_pEX poly_type; ZZ_pX _ZZ_pE__rep; // static data static long DivCross() { return 16; } static long ModCross() { return 8; } // ****** constructors and assignment ZZ_pE() { } // NO_ALLOC explicit ZZ_pE(long a) { *this = a; } // NO_ALLOC explicit ZZ_pE(const ZZ_p& a) { *this = a; } // NO_ALLOC ZZ_pE(INIT_NO_ALLOC_TYPE) { } // allocates no space ZZ_pE(INIT_ALLOC_TYPE) {_ZZ_pE__rep.rep.SetMaxLength(ZZ_pE::degree()); } // allocates space void allocate() { _ZZ_pE__rep.rep.SetMaxLength(ZZ_pE::degree()); } inline ZZ_pE& operator=(long a); inline ZZ_pE& operator=(const ZZ_p& a); ZZ_pE(ZZ_pE& x, INIT_TRANS_TYPE) : _ZZ_pE__rep(x._ZZ_pE__rep, INIT_TRANS) { } void swap(ZZ_pE& x) { _ZZ_pE__rep.swap(x._ZZ_pE__rep); } // You can always access the _ZZ_pE__representation directly...if you dare. ZZ_pX& LoopHole() { return _ZZ_pE__rep; } static const ZZ_pXModulus& modulus() { return ZZ_pEInfo->p; } static long degree() { return deg(ZZ_pEInfo->p); } static const ZZ& cardinality(); static const ZZ_pE& zero(); static long initialized() { return (ZZ_pEInfo != 0); } static void init(const ZZ_pX&); }; NTL_DECLARE_RELOCATABLE((ZZ_pE*)) // read-only access to _ZZ_pE__representation inline const ZZ_pX& rep(const ZZ_pE& a) { return a._ZZ_pE__rep; } inline void clear(ZZ_pE& x) // x = 0 { clear(x._ZZ_pE__rep); } inline void set(ZZ_pE& x) // x = 1 { set(x._ZZ_pE__rep); } inline void swap(ZZ_pE& x, ZZ_pE& y) // swap x and y { x.swap(y); } // ****** addition inline void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a + b { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a - b { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep); } inline void negate(ZZ_pE& x, const ZZ_pE& a) { negate(x._ZZ_pE__rep, a._ZZ_pE__rep); } inline void add(ZZ_pE& x, const ZZ_pE& a, long b) { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { add(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void add(ZZ_pE& x, long a, const ZZ_pE& b) { add(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void add(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { add(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_pE& a, long b) { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { sub(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void sub(ZZ_pE& x, long a, const ZZ_pE& b) { sub(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void sub(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { sub(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } // ****** multiplication inline void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b) // x = a*b { MulMod(x._ZZ_pE__rep, a._ZZ_pE__rep, b._ZZ_pE__rep, ZZ_pE::modulus()); } inline void sqr(ZZ_pE& x, const ZZ_pE& a) // x = a^2 { SqrMod(x._ZZ_pE__rep, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_pE sqr(const ZZ_pE& a) { ZZ_pE x; sqr(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline void mul(ZZ_pE& x, const ZZ_pE& a, long b) { mul(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b) { mul(x._ZZ_pE__rep, a._ZZ_pE__rep, b); } inline void mul(ZZ_pE& x, long a, const ZZ_pE& b) { mul(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } inline void mul(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b) { mul(x._ZZ_pE__rep, a, b._ZZ_pE__rep); } // ****** division void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); void div(ZZ_pE& x, const ZZ_pE& a, long b); void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_p& b); void div(ZZ_pE& x, long a, const ZZ_pE& b); void div(ZZ_pE& x, const ZZ_p& a, const ZZ_pE& b); void inv(ZZ_pE& x, const ZZ_pE& a); inline ZZ_pE inv(const ZZ_pE& a) { ZZ_pE x; inv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } // ****** exponentiation inline void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e) // x = a^e { PowerMod(x._ZZ_pE__rep, a._ZZ_pE__rep, e, ZZ_pE::modulus()); } inline ZZ_pE power(const ZZ_pE& a, const ZZ& e) { ZZ_pE x; power(x, a, e); NTL_OPT_RETURN(ZZ_pE, x); } inline void power(ZZ_pE& x, const ZZ_pE& a, long e) { power(x, a, ZZ_expo(e)); } inline ZZ_pE power(const ZZ_pE& a, long e) { ZZ_pE x; power(x, a, e); NTL_OPT_RETURN(ZZ_pE, x); } // ****** conversion inline void conv(ZZ_pE& x, const ZZ_pX& a) { rem(x._ZZ_pE__rep, a, ZZ_pE::modulus()); } inline void conv(ZZ_pE& x, long a) { conv(x._ZZ_pE__rep, a); } inline void conv(ZZ_pE& x, const ZZ_p& a) { conv(x._ZZ_pE__rep, a); } inline void conv(ZZ_pE& x, const ZZ& a) { conv(x._ZZ_pE__rep, a); } inline ZZ_pE to_ZZ_pE(const ZZ_pX& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(long a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(const ZZ_p& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE to_ZZ_pE(const ZZ& a) { ZZ_pE x; conv(x, a); NTL_OPT_RETURN(ZZ_pE, x); } // ****** comparison inline long IsZero(const ZZ_pE& a) { return IsZero(a._ZZ_pE__rep); } inline long IsOne(const ZZ_pE& a) { return IsOne(a._ZZ_pE__rep); } inline long operator==(const ZZ_pE& a, const ZZ_pE& b) { return a._ZZ_pE__rep == b._ZZ_pE__rep; } inline long operator==(const ZZ_pE& a, long b) { return a._ZZ_pE__rep == b; } inline long operator==(const ZZ_pE& a, const ZZ_p& b) { return a._ZZ_pE__rep == b; } inline long operator==(long a, const ZZ_pE& b) { return a == b._ZZ_pE__rep; } inline long operator==(const ZZ_p& a, const ZZ_pE& b) { return a == b._ZZ_pE__rep; } inline long operator!=(const ZZ_pE& a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(long a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pE& b) { return !(a == b); } // ****** norm and trace inline void trace(ZZ_p& x, const ZZ_pE& a) { TraceMod(x, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_p trace(const ZZ_pE& a) { return TraceMod(a._ZZ_pE__rep, ZZ_pE::modulus()); } inline void norm(ZZ_p& x, const ZZ_pE& a) { NormMod(x, a._ZZ_pE__rep, ZZ_pE::modulus()); } inline ZZ_p norm(const ZZ_pE& a) { return NormMod(a._ZZ_pE__rep, ZZ_pE::modulus()); } // ****** random numbers inline void random(ZZ_pE& x) // x = random element in ZZ_pE { random(x._ZZ_pE__rep, ZZ_pE::degree()); } inline ZZ_pE random_ZZ_pE() { ZZ_pE x; random(x); NTL_OPT_RETURN(ZZ_pE, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pE& a) { return s << a._ZZ_pE__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pE& x); inline ZZ_pE& ZZ_pE::operator=(long a) { conv(*this, a); return *this; } inline ZZ_pE& ZZ_pE::operator=(const ZZ_p& a) { conv(*this, a); return *this; } inline ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_pE& a, long b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator+(long a, const ZZ_pE& b) { ZZ_pE x; add(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a, long b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(long a, const ZZ_pE& b) { ZZ_pE x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator-(const ZZ_pE& a) { ZZ_pE x; negate(x, a); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& b) { add(x, x, b); return x; } inline ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pE& operator+=(ZZ_pE& x, long b) { add(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& b) { sub(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pE& operator-=(ZZ_pE& x, long b) { sub(x, x, b); return x; } inline ZZ_pE& operator++(ZZ_pE& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pE& x, int) { add(x, x, 1); } inline ZZ_pE& operator--(ZZ_pE& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pE& x, int) { sub(x, x, 1); } inline ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_pE& a, long b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator*(long a, const ZZ_pE& b) { ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& b) { mul(x, x, b); return x; } inline ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pE& operator*=(ZZ_pE& x, long b) { mul(x, x, b); return x; } inline ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_pE& a, const ZZ_p& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_pE& a, long b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(const ZZ_p& a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE operator/(long a, const ZZ_pE& b) { ZZ_pE x; div(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } inline ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& b) { div(x, x, b); return x; } inline ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pE& operator/=(ZZ_pE& x, long b) { div(x, x, b); return x; } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pX& x, const ZZ_pE& a) { x = rep(a); } inline void conv(ZZ_pE& x, const ZZ_pE& a) { x = a; } /* ------------------------------------- */ NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_pEX.h0000644417616742025610000007537114064716022017542 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_pEX__H #define NTL_ZZ_pEX__H #include #include NTL_OPEN_NNS class ZZ_pEXModulus; // forward declaration class ZZ_pEX { public: typedef ZZ_pE coeff_type; typedef ZZ_pEXModulus modulus_type; vec_ZZ_pE rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZ_pEX() { } // initial value 0 explicit ZZ_pEX(long a) { *this = a; } explicit ZZ_pEX(const ZZ_p& a) { *this = a; } explicit ZZ_pEX(const ZZ_pE& a) { *this = a; } ZZ_pEX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } // default copy constructor and assignment // defaut destructor void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } ZZ_pE& operator[](long i) { return rep[i]; } const ZZ_pE& operator[](long i) const { return rep[i]; } static const ZZ_pEX& zero(); inline ZZ_pEX(long i, const ZZ_pE& c); inline ZZ_pEX(long i, const ZZ_p& c); inline ZZ_pEX(long i, long c); inline ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c); inline ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c); inline ZZ_pEX(INIT_MONO_TYPE, long i, long c); inline ZZ_pEX(INIT_MONO_TYPE, long i); inline ZZ_pEX& operator=(long a); inline ZZ_pEX& operator=(const ZZ_p& a); inline ZZ_pEX& operator=(const ZZ_pE& a); ZZ_pEX(ZZ_pEX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } void swap(ZZ_pEX& x) { rep.swap(x.rep); } }; NTL_DECLARE_RELOCATABLE((ZZ_pEX*)) NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pEX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pEX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZ_pEX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ_pE& coeff(const ZZ_pEX& a, long i); // zero if i not in range const ZZ_pE& LeadCoeff(const ZZ_pEX& a); // zero if a == 0 const ZZ_pE& ConstTerm(const ZZ_pEX& a); // zero if a == 0 void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a); void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pEX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZ_pEX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pEX::ZZ_pEX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZ_pEX& x); // x is set to the monomial X long IsX(const ZZ_pEX& a); // test if x = X inline void clear(ZZ_pEX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZ_pEX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZ_pEX& x, ZZ_pEX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void random(ZZ_pEX& x, long n); inline ZZ_pEX random_ZZ_pEX(long n) { ZZ_pEX x; random(x, n); NTL_OPT_RETURN(ZZ_pEX, x); } // generate a random polynomial of degree < n void trunc(ZZ_pEX& x, const ZZ_pEX& a, long m); inline ZZ_pEX trunc(const ZZ_pEX& a, long m) { ZZ_pEX x; trunc(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a % X^m void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX RightShift(const ZZ_pEX& a, long n) { ZZ_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a/X^n void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX LeftShift(const ZZ_pEX& a, long n) { ZZ_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline ZZ_pEX operator>>(const ZZ_pEX& a, long n) { ZZ_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator<<(const ZZ_pEX& a, long n) { ZZ_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator<<=(ZZ_pEX& x, long n) { LeftShift(x, x, n); return x; } inline ZZ_pEX& operator>>=(ZZ_pEX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZ_pEX& x, const ZZ_pEX& a); inline ZZ_pEX diff(const ZZ_pEX& a) { ZZ_pEX x; diff(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // x = derivative of a void MakeMonic(ZZ_pEX& x); void reverse(ZZ_pEX& c, const ZZ_pEX& a, long hi); inline ZZ_pEX reverse(const ZZ_pEX& a, long hi) { ZZ_pEX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZ_pEX, x); } inline void reverse(ZZ_pEX& c, const ZZ_pEX& a) { reverse(c, a, deg(a)); } inline ZZ_pEX reverse(const ZZ_pEX& a) { ZZ_pEX x; reverse(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZ_pEX& x, long a); void conv(ZZ_pEX& x, const ZZ& a); void conv(ZZ_pEX& x, const ZZ_p& a); void conv(ZZ_pEX& x, const ZZ_pX& a); void conv(ZZ_pEX& x, const ZZ_pE& a); void conv(ZZ_pEX& x, const vec_ZZ_pE& a); inline ZZ_pEX to_ZZ_pEX(long a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_p& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_pX& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const ZZ_pE& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX to_ZZ_pEX(const vec_ZZ_pE& a) { ZZ_pEX x; conv(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& ZZ_pEX::operator=(long a) { conv(*this, a); return *this; } inline ZZ_pEX& ZZ_pEX::operator=(const ZZ_p& a) { conv(*this, a); return *this; } inline ZZ_pEX& ZZ_pEX::operator=(const ZZ_pE& a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pEX& x, const ZZ_pEX& a) { x = a; } inline void conv(vec_ZZ_pE& x, const ZZ_pEX& a) { x = a.rep; } class ZZX; void conv(ZZ_pEX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZ_pEX& a); long IsOne(const ZZ_pEX& a); inline long operator==(const ZZ_pEX& a, const ZZ_pEX& b) { return a.rep == b.rep; } long operator==(const ZZ_pEX& a, long b); long operator==(const ZZ_pEX& a, const ZZ_p& b); long operator==(const ZZ_pEX& a, const ZZ_pE& b); inline long operator==(long a, const ZZ_pEX& b) { return (b == a); } inline long operator==(const ZZ_p& a, const ZZ_pEX& b) { return (b == a); } inline long operator==(const ZZ_pE& a, const ZZ_pEX& b) { return (b == a); } inline long operator!=(const ZZ_pEX& a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(const ZZ_pEX& a, const ZZ_pE& b) { return !(a == b); } inline long operator!=(const long a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pEX& b) { return !(a == b); } inline long operator!=(const ZZ_pE& a, const ZZ_pEX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); void negate(ZZ_pEX& x, const ZZ_pEX& a); // scalar versions void add(ZZ_pEX & x, const ZZ_pEX& a, long b); void add(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void add(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); inline void add(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b) { add(x, b, a); } inline void add(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { add(x, b, a); } inline void add(ZZ_pEX& x, long a, const ZZ_pEX& b) { add(x, b, a); } void sub(ZZ_pEX & x, const ZZ_pEX& a, long b); void sub(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void sub(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); void sub(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b); void sub(ZZ_pEX& x, long a, const ZZ_pEX& b); inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pEX& a, long b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator+(long a, const ZZ_pEX& b) { ZZ_pEX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pEX& a, long b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator-(long a, const ZZ_pEX& b) { ZZ_pEX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pEX& operator+=(ZZ_pEX& x, long b) { add(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pEX& operator-=(ZZ_pEX& x, long b) { sub(x, x, b); return x; } inline ZZ_pEX operator-(const ZZ_pEX& a) { ZZ_pEX x; negate(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator++(ZZ_pEX& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pEX& x, int) { add(x, x, 1); } inline ZZ_pEX& operator--(ZZ_pEX& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pEX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b void sqr(ZZ_pEX& x, const ZZ_pEX& a); inline ZZ_pEX sqr(const ZZ_pEX& a) { ZZ_pEX x; sqr(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^2 void mul(ZZ_pEX & x, const ZZ_pEX& a, long b); void mul(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_p& b); void mul(ZZ_pEX & x, const ZZ_pEX& a, const ZZ_pE& b); inline void mul(ZZ_pEX& x, long a, const ZZ_pEX& b) { mul(x, b, a); } inline void mul(ZZ_pEX& x, const ZZ_p& a, const ZZ_pEX& b) { mul(x, b, a); } inline void mul(ZZ_pEX& x, const ZZ_pE& a, const ZZ_pEX& b) { mul(x, b, a); } void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n); inline ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n) { ZZ_pEX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a * b % X^n void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); inline ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n) { ZZ_pEX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a*a % X^n inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pEX& a, long b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_pE& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(const ZZ_p& a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator*(long a, const ZZ_pEX& b) { ZZ_pEX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pEX& operator*=(ZZ_pEX& x, long b) { mul(x, x, b); return x; } void power(ZZ_pEX& x, const ZZ_pEX& a, long e); inline ZZ_pEX power(const ZZ_pEX& a, long e) { ZZ_pEX x; power(x, a, e); NTL_OPT_RETURN(ZZ_pEX, x); } /************************************************************* Division **************************************************************/ void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // q = a/b, r = a%b void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b); void div(ZZ_pEX& q, const ZZ_pEX& a, long b); // q = a/b void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // r = a%b long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long m); inline ZZ_pEX InvTrunc(const ZZ_pEX& a, long m) { ZZ_pEX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } // computes x = a^{-1} % X^m // constant term must be invertible inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator/(const ZZ_pEX& a, long b) { ZZ_pEX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pEX& operator/=(ZZ_pEX& x, long b) { div(x, x, b); return x; } inline ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; rem(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); inline ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pEX x; GCD(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the ZZ_pEXModulus data structure and associated routines below. void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); inline ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f) { ZZ_pEX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = (a * b) % f void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^2 % f void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = (a * X) mod f void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pEX x; InvMod(x, a, f); NTL_OPT_RETURN(ZZ_pEX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build ZZ_pEXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class ZZ_pEXModulus { public: ZZ_pEXModulus(); ~ZZ_pEXModulus(); ZZ_pEXModulus(const ZZ_pEX& ff); ZZ_pEX f; // the modulus operator const ZZ_pEX& () const { return f; } const ZZ_pEX& val() const { return f; } long n; // deg(f) long method; ZZ_pEX h0; ZZ_pE hlc; ZZ_pEX f0; OptionalVal< Lazy > tracevec; // extra level of indirection to ensure relocatability }; NTL_DECLARE_RELOCATABLE((ZZ_pEXModulus*)) inline long deg(const ZZ_pEXModulus& F) { return F.n; } void build(ZZ_pEXModulus& F, const ZZ_pEX& f); void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F); void MulMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); inline ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F) { ZZ_pEX x; MulMod(x, a, b, F); NTL_OPT_RETURN(ZZ_pEX, x); } void SqrMod(ZZ_pEX& c, const ZZ_pEX& a, const ZZ_pEXModulus& F); inline ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; SqrMod(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F); inline void PowerMod(ZZ_pEX& h, const ZZ_pEX& g, long e, const ZZ_pEXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline ZZ_pEX PowerMod(const ZZ_pEX& g, const ZZ& e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX PowerMod(const ZZ_pEX& g, long e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } void PowerXMod(ZZ_pEX& hh, const ZZ& e, const ZZ_pEXModulus& F); inline void PowerXMod(ZZ_pEX& h, long e, const ZZ_pEXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; rem(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F) { rem(x, x, F); return x; } inline ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pEX x; div(x, a, F); NTL_OPT_RETURN(ZZ_pEX, x); } inline ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of ZZ_pEX's *****************************************************************/ typedef Vec vec_ZZ_pEX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a); inline ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a) { ZZ_pEX x; BuildFromRoots(x, a); NTL_OPT_RETURN(ZZ_pEX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a); inline ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a) { ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(ZZ_pE, x); } // b = f(a) void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a); inline vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a) { vec_ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(vec_ZZ_pE, x); } // b[i] = f(a[i]) inline void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a) { conv(b, CompMod(f, rep(a), ZZ_pE::modulus())); } inline ZZ_pE eval(const ZZ_pX& f, const ZZ_pE& a) { ZZ_pE x; eval(x, f, a); NTL_OPT_RETURN(ZZ_pE, x); } // b = f(a) void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b); inline ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b) { ZZ_pEX x; interpolate(x, a, b); NTL_OPT_RETURN(ZZ_pEX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ZZ_pEX x; CompMod(x, g, h, F); NTL_OPT_RETURN(ZZ_pEX, x); } // x = g(h) mod f void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If ZZ_pEXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If ZZ_pEXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, ZZ_pEXArgBound = 0. // If a single h is going to be used with many g's // then you should build a ZZ_pEXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If ZZ_pEXArgBound > 0, a table of size less than m may be built. struct ZZ_pEXArgument { vec_ZZ_pEX H; }; extern NTL_CHEAP_THREAD_LOCAL long ZZ_pEXArgBound; void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); inline ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { ZZ_pEX x; CompMod(x, g, H, F); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m); inline ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m) { ZZ_pEX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void MinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } void ProbMinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void ProbMinPolyMod(ZZ_pEX& hh, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); inline ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pEX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pEX, x); } void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pEX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pEX, x); } struct ZZ_pEXTransMultiplier { ZZ_pEX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F); void TransMulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F); void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F); inline vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a, const ZZ_pEXTransMultiplier& B, const ZZ_pEXModulus& F) { vec_ZZ_pE x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); inline vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F) { vec_ZZ_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEX& H, const ZZ_pEXModulus& F) { vec_ZZ_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline void project(ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEX& b) { InnerProduct(x, a, b.rep); } inline ZZ_pE project(const vec_ZZ_pE& a, const ZZ_pEX& b) { ZZ_pE x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(ZZ_pE, x); } /***************************************************************** modular composition and minimal polynonomials in towers ******************************************************************/ // composition void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F); inline ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& A, const ZZ_pEXModulus& F) { ZZ_pEX x; CompTower(x, g, A, F); NTL_OPT_RETURN(ZZ_pEX, x); } void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); inline ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F) { ZZ_pEX x; CompTower(x, g, h, F); NTL_OPT_RETURN(ZZ_pEX, x); } // prob min poly void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // min poly void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { MinPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; MinPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // irred poly void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); inline ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m) { ZZ_pX x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F) { IrredPolyTower(h, g, F, deg(F)*ZZ_pE::degree()); } inline ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F) { ZZ_pX x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f); inline vec_ZZ_pE TraceVec(const ZZ_pEX& f) { vec_ZZ_pE x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ_pE, x); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); inline ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F) { ZZ_pE x; TraceMod(x, a, F); NTL_OPT_RETURN(ZZ_pE, x); } void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pE x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ_pE, x); } void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); inline ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f) { ZZ_pE x; NormMod(x, a, f); NTL_OPT_RETURN(ZZ_pE, x); } void resultant(ZZ_pE& rres, const ZZ_pEX& a, const ZZ_pEX& b); inline ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b) { ZZ_pE x; resultant(x, a, b); NTL_OPT_RETURN(ZZ_pE, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_pEXFactoring.h0000644417616742025610000001233514064716022021366 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_pEXFactoring__H #define NTL_ZZ_pEXFactoring__H #include NTL_OPEN_NNS void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f); inline vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f) { vec_pair_ZZ_pEX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f); inline vec_ZZ_pE FindRoots(const ZZ_pEX& f) { vec_ZZ_pE x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(ZZ_pE& root, const ZZ_pEX& f); inline ZZ_pE FindRoot(const ZZ_pEX& f) { ZZ_pE x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors extern NTL_CHEAP_THREAD_LOCAL long ZZ_pEX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF extern NTL_CHEAP_THREAD_LOCAL double ZZ_pEXFileThresh; // of these tables exceeds ZZ_pEXFileThresh KB. void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); inline vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0) { vec_pair_ZZ_pEX_long x; NewDDF(x, f, h, verbose); return x; } void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose=0); inline vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& b, long d, long verbose=0) { vec_ZZ_pEX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); inline vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0) { vec_ZZ_pEX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); inline vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0) { vec_ZZ_pEX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose=0); inline vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0) { vec_pair_ZZ_pEX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v); inline ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v) { ZZ_pEX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const ZZ_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const ZZ_pEX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const ZZ_pEX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pEX& f, long n); inline ZZ_pEX BuildIrred_ZZ_pEX(long n) { ZZ_pEX x; BuildIrred(x, n); NTL_OPT_RETURN(ZZ_pEX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g); inline ZZ_pEX BuildRandomIrred(const ZZ_pEX& g) { ZZ_pEX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(ZZ_pEX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b); inline ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& b) { ZZ_pEX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F); inline ZZ_pEX PowerCompose(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F) { ZZ_pEX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_pX.h0000644417616742025610000011162614064716022017427 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_pX__H #define NTL_ZZ_pX__H #include #include #include #include #include #include #include #ifndef NTL_WIZARD_HACK #include #endif NTL_OPEN_NNS // some cross-over points // macros are used so as to be consistent with zz_pX #define NTL_ZZ_pX_FFT_CROSSOVER (20) #define NTL_ZZ_pX_NEWTON_CROSSOVER (45) #define NTL_ZZ_pX_DIV_CROSSOVER (90) #define NTL_ZZ_pX_HalfGCD_CROSSOVER (25) #define NTL_ZZ_pX_GCD_CROSSOVER (180) #define NTL_ZZ_pX_BERMASS_CROSSOVER (90) #define NTL_ZZ_pX_TRACE_CROSSOVER (90) /************************************************************ ZZ_pX The class ZZ_pX implements polynomial arithmetic modulo p. Polynomials are represented as vec_ZZ_p's. If f is a ZZ_pX, then f.rep is a vec_ZZ_p. The zero polynomial is represented as a zero length vector. Otherwise. f.rep[0] is the constant-term, and f.rep[f.rep.length()-1] is the leading coefficient, which is always non-zero. The member f.rep is public, so the vector representation is fully accessible. Use the member function normalize() to strip leading zeros. **************************************************************/ class ZZ_pE; // forward declaration class ZZ_pXModulus; class FFTRep; class ZZ_pXMultiplier; class ZZ_pX { public: typedef ZZ_p coeff_type; typedef ZZ_pE residue_type; typedef ZZ_pXModulus modulus_type; typedef ZZ_pXMultiplier multiplier_type; typedef FFTRep fft_type; typedef vec_ZZ_p VectorBaseType; vec_ZZ_p rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ ZZ_pX() { } // initial value 0 explicit ZZ_pX(long a) { *this = a; } explicit ZZ_pX(const ZZ_p& a) { *this = a; } ZZ_pX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } // default copy constrctor and assignment // default destructor void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } ZZ_p& operator[](long i) { return rep[i]; } const ZZ_p& operator[](long i) const { return rep[i]; } static const ZZ_pX& zero(); ZZ_pX(ZZ_pX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } inline ZZ_pX(long i, const ZZ_p& c); inline ZZ_pX(long i, long c); inline ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c); inline ZZ_pX(INIT_MONO_TYPE, long i, long c); inline ZZ_pX(INIT_MONO_TYPE, long i); ZZ_pX& operator=(long a); ZZ_pX& operator=(const ZZ_p& a); void swap(ZZ_pX& x) { rep.swap(x.rep); } }; NTL_DECLARE_RELOCATABLE((ZZ_pX*)) /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are then reduced modulo p, and leading zeros stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, ZZ_pX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const ZZ_pX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const ZZ_pX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const ZZ_p& coeff(const ZZ_pX& a, long i); // zero if i not in range void GetCoeff(ZZ_p& x, const ZZ_pX& a, long i); // x = a[i], or zero if i not in range const ZZ_p& LeadCoeff(const ZZ_pX& a); // zero if a == 0 const ZZ_p& ConstTerm(const ZZ_pX& a); // zero if a == 0 void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a); // x[i] = a, error is raised if i < 0 void SetCoeff(ZZ_pX& x, long i, long a); void SetCoeff(ZZ_pX& x, long i); // x[i] = 1, error is raised if i < 0 inline ZZ_pX::ZZ_pX(long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline ZZ_pX::ZZ_pX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(ZZ_pX& x); // x is set to the monomial X long IsX(const ZZ_pX& a); // test if a = X inline void clear(ZZ_pX& x) // x = 0 { x.rep.SetLength(0); } inline void set(ZZ_pX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(ZZ_pX& x, ZZ_pX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void random(ZZ_pX& x, long n); inline ZZ_pX random_ZZ_pX(long n) { ZZ_pX x; random(x, n); NTL_OPT_RETURN(ZZ_pX, x); } // generate a random polynomial of degree < n void trunc(ZZ_pX& x, const ZZ_pX& a, long m); // x = a % X^m inline ZZ_pX trunc(const ZZ_pX& a, long m) { ZZ_pX x; trunc(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } void RightShift(ZZ_pX& x, const ZZ_pX& a, long n); // x = a/X^n inline ZZ_pX RightShift(const ZZ_pX& a, long n) { ZZ_pX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n); // x = a*X^n inline ZZ_pX LeftShift(const ZZ_pX& a, long n) { ZZ_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } #ifndef NTL_TRANSITION inline ZZ_pX operator>>(const ZZ_pX& a, long n) { ZZ_pX x; RightShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator<<(const ZZ_pX& a, long n) { ZZ_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator<<=(ZZ_pX& x, long n) { LeftShift(x, x, n); return x; } inline ZZ_pX& operator>>=(ZZ_pX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a inline ZZ_pX diff(const ZZ_pX& a) { ZZ_pX x; diff(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void MakeMonic(ZZ_pX& x); void reverse(ZZ_pX& c, const ZZ_pX& a, long hi); inline ZZ_pX reverse(const ZZ_pX& a, long hi) { ZZ_pX x; reverse(x, a, hi); NTL_OPT_RETURN(ZZ_pX, x); } inline void reverse(ZZ_pX& c, const ZZ_pX& a) { reverse(c, a, deg(a)); } inline ZZ_pX reverse(const ZZ_pX& a) { ZZ_pX x; reverse(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_ZZ_p VectorCopy(const ZZ_pX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(ZZ_pX& x, long a); void conv(ZZ_pX& x, const ZZ& a); void conv(ZZ_pX& x, const ZZ_p& a); void conv(ZZ_pX& x, const vec_ZZ_p& a); inline ZZ_pX to_ZZ_pX(long a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const ZZ& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const ZZ_p& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX to_ZZ_pX(const vec_ZZ_p& a) { ZZ_pX x; conv(x, a); NTL_OPT_RETURN(ZZ_pX, x); } /* additional legacy conversions for v6 conversion regime */ inline void conv(ZZ_pX& x, const ZZ_pX& a) { x = a; } inline void conv(vec_ZZ_p& x, const ZZ_pX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const ZZ_pX& a); long IsOne(const ZZ_pX& a); inline long operator==(const ZZ_pX& a, const ZZ_pX& b) { return a.rep == b.rep; } inline long operator!=(const ZZ_pX& a, const ZZ_pX& b) { return !(a == b); } long operator==(const ZZ_pX& a, long b); long operator==(const ZZ_pX& a, const ZZ_p& b); inline long operator==(long a, const ZZ_pX& b) { return b == a; } inline long operator==(const ZZ_p& a, const ZZ_pX& b) { return b == a; } inline long operator!=(const ZZ_pX& a, long b) { return !(a == b); } inline long operator!=(const ZZ_pX& a, const ZZ_p& b) { return !(a == b); } inline long operator!=(long a, const ZZ_pX& b) { return !(a == b); } inline long operator!=(const ZZ_p& a, const ZZ_pX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a // scalar versions void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b); // x = a + b void add(ZZ_pX& x, const ZZ_pX& a, long b); inline void add(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { add(x, b, a); } inline void add(ZZ_pX& x, long a, const ZZ_pX& b) { add(x, b, a); } void sub(ZZ_pX & x, const ZZ_pX& a, const ZZ_p& b); // x = a - b void sub(ZZ_pX& x, const ZZ_pX& a, long b); void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_p& b); void sub(ZZ_pX& x, long a, const ZZ_pX& b); void sub(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b); inline ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_pX& a, long b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator+(long a, const ZZ_pX& b) { ZZ_pX x; add(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_pX& a, long b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator-(long a, const ZZ_pX& b) { ZZ_pX x; sub(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& b) { add(x, x, b); return x; } inline ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& b) { add(x, x, b); return x; } inline ZZ_pX& operator+=(ZZ_pX& x, long b) { add(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& b) { sub(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& b) { sub(x, x, b); return x; } inline ZZ_pX& operator-=(ZZ_pX& x, long b) { sub(x, x, b); return x; } inline ZZ_pX operator-(const ZZ_pX& a) { ZZ_pX x; negate(x, a); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator++(ZZ_pX& x) { add(x, x, 1); return x; } inline void operator++(ZZ_pX& x, int) { add(x, x, 1); } inline ZZ_pX& operator--(ZZ_pX& x) { sub(x, x, 1); return x; } inline void operator--(ZZ_pX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b void sqr(ZZ_pX& x, const ZZ_pX& a); inline ZZ_pX sqr(const ZZ_pX& a) { ZZ_pX x; sqr(x, a); NTL_OPT_RETURN(ZZ_pX, x); } // x = a^2 void mul(ZZ_pX & x, const ZZ_pX& a, const ZZ_p& b); void mul(ZZ_pX& x, const ZZ_pX& a, long b); inline void mul(ZZ_pX& x, const ZZ_p& a, const ZZ_pX& b) { mul(x, b, a); } inline void mul(ZZ_pX& x, long a, const ZZ_pX& b) { mul(x, b, a); } inline ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_pX& a, long b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(const ZZ_p& a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator*(long a, const ZZ_pX& b) { ZZ_pX x; mul(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& b) { mul(x, x, b); return x; } inline ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& b) { mul(x, x, b); return x; } inline ZZ_pX& operator*=(ZZ_pX& x, long b) { mul(x, x, b); return x; } void PlainMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses the "classical" algorithm void PlainSqr(ZZ_pX& x, const ZZ_pX& a); // always uses the "classical" algorithm void FFTMul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses the FFT void FFTSqr(ZZ_pX& x, const ZZ_pX& a); // always uses the FFT void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); // x = a * b % X^n inline ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n) { ZZ_pX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(ZZ_pX, x); } void PlainMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); void FFTMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a^2 % X^n inline ZZ_pX SqrTrunc(const ZZ_pX& a, long n) { ZZ_pX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(ZZ_pX, x); } void PlainSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); void FFTSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); void power(ZZ_pX& x, const ZZ_pX& a, long e); inline ZZ_pX power(const ZZ_pX& a, long e) { ZZ_pX x; power(x, a, e); NTL_OPT_RETURN(ZZ_pX, x); } // The following data structures and routines allow one // to hand-craft various algorithms, using the FFT convolution // algorithms directly. // Look in the file ZZ_pX.c for examples. // FFT representation of polynomials class FFTRep { public: long k; // a 2^k point representation long MaxK; // maximum space allocated long len; // length of truncated FFT long NumPrimes; Unique2DArray tbl; FFTRep() : k(-1), MaxK(-1), len(0), NumPrimes(0) { } FFTRep(const FFTRep& R) : k(-1), MaxK(-1), len(0), NumPrimes(0) { *this = R; } FFTRep(INIT_SIZE_TYPE, long InitK) : k(-1), MaxK(-1), len(0), NumPrimes(0) { SetSize(InitK); } FFTRep& operator=(const FFTRep& R); void SetSize(long NewK); void DoSetSize(long NewK, long NewNumPrimes); }; void ToFFTRep_trunc(FFTRep& y, const ZZ_pX& x, long k, long len, long lo, long hi); inline void ToFFTRep_trunc(FFTRep& y, const ZZ_pX& x, long k, long len) { ToFFTRep_trunc(y, x, k, len, 0, deg(x)); } inline void ToFFTRep(FFTRep& y, const ZZ_pX& x, long k, long lo, long hi) // computes an n = 2^k point convolution of x[lo..hi]. { ToFFTRep_trunc(y, x, k, 1L << k, lo, hi); } inline void ToFFTRep(FFTRep& y, const ZZ_pX& x, long k) { ToFFTRep(y, x, k, 0, deg(x)); } void RevToFFTRep(FFTRep& y, const vec_ZZ_p& x, long k, long lo, long hi, long offset); // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. void FromFFTRep(ZZ_pX& x, FFTRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed // NOTE: this version destroys the data in y // non-destructive versions of the above void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi, FFTRep& temp); void NDFromFFTRep(ZZ_pX& x, const FFTRep& y, long lo, long hi); void RevFromFFTRep(vec_ZZ_p& x, FFTRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed void FromFFTRep(ZZ_p* x, FFTRep& y, long lo, long hi); // convert out coefficients lo..hi of y, store result in x. // no normalization is done. // direct manipulation of FFT reps void mul(FFTRep& z, const FFTRep& x, const FFTRep& y); void sub(FFTRep& z, const FFTRep& x, const FFTRep& y); void add(FFTRep& z, const FFTRep& x, const FFTRep& y); void reduce(FFTRep& x, const FFTRep& a, long k); // reduces a 2^l point FFT-rep to a 2^k point FFT-rep void AddExpand(FFTRep& x, const FFTRep& a); // x = x + (an "expanded" version of a) // This data structure holds unconvoluted modular representations // of polynomials class ZZ_pXModRep { private: ZZ_pXModRep(const ZZ_pXModRep&); // disabled void operator=(const ZZ_pXModRep&); // disabled public: long n; long MaxN; long NumPrimes; Unique2DArray tbl; void SetSize(long NewN); ZZ_pXModRep() : n(0), MaxN(0), NumPrimes(0) { } ZZ_pXModRep(INIT_SIZE_TYPE, long NewN) : n(0), MaxN(0), NumPrimes(0) { SetSize(NewN); } }; void ToZZ_pXModRep(ZZ_pXModRep& x, const ZZ_pX& a, long lo, long hi); void ToFFTRep(FFTRep& x, const ZZ_pXModRep& a, long k, long lo, long hi); // converts coefficients lo..hi to a 2^k-point FFTRep. // must have hi-lo+1 < 2^k void FromFFTRep(ZZ_pXModRep& x, const FFTRep& a); // for testing and timing purposes only -- converts from FFTRep void FromZZ_pXModRep(ZZ_pX& x, const ZZ_pXModRep& a, long lo, long hi); // for testing and timing purposes only -- converts from ZZ_pXModRep /************************************************************* Division **************************************************************/ void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // q = a/b, r = a%b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // q = a/b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b); void div(ZZ_pX& q, const ZZ_pX& a, long b); void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // r = a%b long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline ZZ_pX InvTrunc(const ZZ_pX& a, long m) { ZZ_pX x; InvTrunc(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } // These always use "classical" arithmetic void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& tmp); void PlainDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b, ZZVec& tmp); // These always use FFT arithmetic void FFTDivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void FFTDiv(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void FFTRem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); void PlainInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // always uses "classical" algorithm // ALIAS RESTRICTION: input may not alias output void NewtonInvTrunc(ZZ_pX& x, const ZZ_pX& a, long m); // uses a Newton Iteration with the FFT. // ALIAS RESTRICTION: input may not alias output inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX operator/(const ZZ_pX& a, long b) { ZZ_pX x; div(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b) { div(x, x, b); return x; } inline ZZ_pX& operator/=(ZZ_pX& x, long b) { div(x, x, b); return x; } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b) { div(x, x, b); return x; } inline ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; rem(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). inline ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b) { ZZ_pX x; GCD(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // d = gcd(a,b), a s + b t = d void PlainXGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // same as above, but uses classical algorithm void PlainGCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // always uses "cdlassical" arithmetic class ZZ_pXMatrix { private: ZZ_pXMatrix(const ZZ_pXMatrix&); // disable ZZ_pX elts[2][2]; public: ZZ_pXMatrix() { } void operator=(const ZZ_pXMatrix&); ZZ_pX& operator() (long i, long j) { return elts[i][j]; } const ZZ_pX& operator() (long i, long j) const { return elts[i][j]; } }; void HalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red); // deg(U) > deg(V), 1 <= d_red <= deg(U)+1. // // This computes a 2 x 2 polynomial matrix M_out such that // M_out * (U, V)^T = (U', V')^T, // where U', V' are consecutive polynomials in the Euclidean remainder // sequence of U, V, and V' is the polynomial of highest degree // satisfying deg(V') <= deg(U) - d_red. void XHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red); // same as above, except that U is replaced by U', and V by V' /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the ZZ_pXModulus data structure and associated routines below. void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); // x = (a * b) % f inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f) { ZZ_pX x; MulMod(x, a, b, f); NTL_OPT_RETURN(ZZ_pX, x); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = a^2 % f inline ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; SqrMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = (a * X) mod f inline ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; MulByXMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // x = a^{-1} % f, error is a is not invertible inline ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; InvMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build ZZ_pXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class ZZ_pXModulus { public: ZZ_pXModulus() : UseFFT(0), n(-1) { } // the following members may become private in future ZZ_pX f; // the modulus long UseFFT;// flag indicating whether FFT should be used. long n; // n = deg(f) long k; // least k s/t 2^k >= n long l; // least l s/t 2^l >= 2n-3 FFTRep FRep; // 2^k point rep of f // H = rev((rev(f))^{-1} rem X^{n-1}) FFTRep HRep; // 2^l point rep of H OptionalVal< Lazy > tracevec; // an extra level of indirection to ensure the class // can be used in a Vec (there may be a mutex in the Lazy object) // but these will remain public ZZ_pXModulus(const ZZ_pX& ff); const ZZ_pX& val() const { return f; } operator const ZZ_pX& () const { return f; } }; NTL_DECLARE_RELOCATABLE((ZZ_pXModulus*)) inline long deg(const ZZ_pXModulus& F) { return F.n; } void build(ZZ_pXModulus& F, const ZZ_pX& f); // deg(f) > 0. void rem21(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f // deg(a) <= 2(n-1), where n = F.n = deg(f) void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f, no restrictions on deg(a); makes repeated calls to rem21 inline ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; rem(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F) { rem(x, x, F); return x; } void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F); void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F); inline ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; div(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } inline ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F) { div(x, x, F); return x; } void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); // x = (a * b) % f // deg(a), deg(b) < n inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F) { ZZ_pX x; MulMod(x, a, b, F); NTL_OPT_RETURN(ZZ_pX, x); } void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a^2 % f // deg(a) < n inline ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_pX x; SqrMod(x, a, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); // x = a^e % f, e >= 0 inline ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F) { PowerMod(x, a, ZZ_expo(e), F); } inline ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F); // x = X^e % f, e >= 0 inline ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(ZZ_pX, x); } void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); // x = (X + a)^e % f, e >= 0 inline ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } inline void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e, const ZZ_pXModulus& F) { PowerXPlusAMod(x, a, ZZ_expo(e), F); } inline ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e, const ZZ_pXModulus& F) { ZZ_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(ZZ_pX, x); } // If you need to compute a * b % f for a fixed b, but for many a's // (for example, computing powers of b modulo f), it is // much more efficient to first build a ZZ_pXMultiplier B for b, // and then use the routine below. class ZZ_pXMultiplier { public: ZZ_pXMultiplier() : UseFFT(0) { } ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F); // the following members may become private in the future ZZ_pX b; long UseFFT; FFTRep B1; FFTRep B2; // but this will remain public const ZZ_pX& val() const { return b; } }; void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F); void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); inline ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { ZZ_pX x; MulMod(x, a, B, F); NTL_OPT_RETURN(ZZ_pX, x); } // x = (a * b) % f /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() inline ZZ_pX BuildFromRoots(const vec_ZZ_p& a) { ZZ_pX x; BuildFromRoots(x, a); NTL_OPT_RETURN(ZZ_pX, x); } void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a); // b = f(a) inline ZZ_p eval(const ZZ_pX& f, const ZZ_p& a) { ZZ_p x; eval(x, f, a); NTL_OPT_RETURN(ZZ_p, x); } void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a); // b[i] = f(a[i]) inline vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a) { vec_ZZ_p x; eval(x, f, a); NTL_OPT_RETURN(vec_ZZ_p, x); } void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b); // computes f such that f(a[i]) = b[i] inline ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b) { ZZ_pX x; interpolate(x, a, b); NTL_OPT_RETURN(ZZ_pX, x); } /***************************************************************** vectors of ZZ_pX's *****************************************************************/ typedef Vec vec_ZZ_pX; /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); // x = g(h) mod f inline ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F) { ZZ_pX x; CompMod(x, g, h, F); NTL_OPT_RETURN(ZZ_pX, x); } void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If ZZ_pXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If ZZ_pXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, ZZ_pXArgBound = 0. // If a single h is going to be used with many g's // then you should build a ZZ_pXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If ZZ_pXArgBound > 0, a table of size less than m may be built. struct ZZ_pXArgument { vec_ZZ_pX H; }; extern NTL_CHEAP_THREAD_LOCAL long ZZ_pXArgBound; void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); inline ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { ZZ_pX x; CompMod(x, g, H, F); NTL_OPT_RETURN(ZZ_pX, x); } // New alternative CompMod strategy that just reduces to // matrix multiplication ... #if (!defined(NTL_WIZARD_HACK) && defined(NTL_HAVE_LL_TYPE)) // NOTE: currently, we only ise the multi-modular matmul NTL_HAVE_LL_TYPE // if NTL_HAVE_LL_TYPE is defined. #define NTL_USE_ZZ_pXNewArgument #endif #ifdef NTL_USE_ZZ_pXNewArgument struct ZZ_pXNewArgument { mat_ZZ_p_opaque mat; ZZ_pX poly; }; void build(ZZ_pXNewArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F); void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F); #else typedef ZZ_pXArgument ZZ_pXNewArgument; #endif #ifndef NTL_TRANSITION void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); inline vec_ZZ_p UpdateMap(const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F) { vec_ZZ_p x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_ZZ_p, x); } #endif /* computes (a, b), (a, (b*X)%f), ..., (a, (b*X^{n-1})%f), where ( , ) denotes the vector inner product. This is really a "transposed" MulMod by B. */ void PlainUpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pX& b, const ZZ_pX& f); // same as above, but uses only classical arithmetic void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); inline vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F) { vec_ZZ_p x; ProjectPowers(x, a, k, h, F); NTL_OPT_RETURN(vec_ZZ_p, x); } // computes (a, 1), (a, h), ..., (a, h^{k-1} % f) // this is really a "transposed" compose. void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); inline vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F) { vec_ZZ_p x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_ZZ_p, x); } // same as above, but uses a pre-computed ZZ_pXArgument inline void project(ZZ_p& x, const vec_ZZ_p& a, const ZZ_pX& b) { InnerProduct(x, a, b.rep); } inline ZZ_p project(const vec_ZZ_p& a, const ZZ_pX& b) { ZZ_p x; project(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; // m is a bound on the degree of the polynomial; // required: a.length() >= 2*m inline ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m) { ZZ_pX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(ZZ_pX, x); } void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } inline ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // computes the monic minimal polynomial if (g mod f). // m = a bound on the degree of the minimal polynomial. // If this argument is not supplied, it defaults to deg(f). // The algorithm is probabilistic, always returns a divisor of // the minimal polynomial, and returns a proper divisor with // probability at most m/p. void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { MinPolyMod(h, g, F, F.n); } inline ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); inline ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m) { ZZ_pX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(ZZ_pX, x); } inline void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F) { IrredPolyMod(h, g, F, F.n); } inline ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F) { ZZ_pX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(ZZ_pX, x); } // same as above, but assumes that f is irreducible, // or at least that the minimal poly of g is itself irreducible. // The algorithm is deterministic (and is always correct). /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_ZZ_p& S, const ZZ_pX& f); inline vec_ZZ_p TraceVec(const ZZ_pX& f) { vec_ZZ_p x; TraceVec(x, f); NTL_OPT_RETURN(vec_ZZ_p, x); } void FastTraceVec(vec_ZZ_p& S, const ZZ_pX& f); void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& f); void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F); inline ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F) { ZZ_p x; TraceMod(x, a, F); NTL_OPT_RETURN(ZZ_p, x); } void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); inline ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_p x; TraceMod(x, a, f); NTL_OPT_RETURN(ZZ_p, x); } void ComputeTraceVec(const ZZ_pXModulus& F); void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); inline ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_p x; NormMod(x, a, f); NTL_OPT_RETURN(ZZ_p, x); } void resultant(ZZ_p& rres, const ZZ_pX& a, const ZZ_pX& b); inline ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b) { ZZ_p x; resultant(x, a, b); NTL_OPT_RETURN(ZZ_p, x); } void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f); // g = char poly of (a mod f) inline ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f) { ZZ_pX x; CharPolyMod(x, a, f); NTL_OPT_RETURN(ZZ_pX, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/ZZ_pXFactoring.h0000644417616742025610000001530614064716022021262 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_ZZ_pXFactoring__H #define NTL_ZZ_pXFactoring__H #include #include #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f); inline vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f) { vec_pair_ZZ_pX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_ZZ_p& x, const ZZ_pX& f); inline vec_ZZ_p FindRoots(const ZZ_pX& f) { vec_ZZ_p x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(ZZ_p& root, const ZZ_pX& f); inline ZZ_p FindRoot(const ZZ_pX& f) { ZZ_p x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX SFBerlekamp(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); inline vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0) { vec_pair_ZZ_pX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. extern NTL_CHEAP_THREAD_LOCAL long ZZ_pX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); inline vec_pair_ZZ_pX_long DDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0) { vec_pair_ZZ_pX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. extern NTL_CHEAP_THREAD_LOCAL long ZZ_pX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF extern NTL_CHEAP_THREAD_LOCAL double ZZ_pXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds ZZ_pXFileThresh KB. void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); inline vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0) { vec_pair_ZZ_pX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& b, long d, long verbose=0); inline vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& b, long d, long verbose=0) { vec_ZZ_pX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); inline vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0) { vec_ZZ_pX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); inline vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0) { vec_pair_ZZ_pX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v); inline ZZ_pX mul(const vec_pair_ZZ_pX_long& v) { ZZ_pX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const ZZ_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const ZZ_pX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const ZZ_pX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pX& f, long n); inline ZZ_pX BuildIrred_ZZ_pX(long n) { ZZ_pX x; BuildIrred(x, n); NTL_OPT_RETURN(ZZ_pX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g); inline ZZ_pX BuildRandomIrred(const ZZ_pX& g) { ZZ_pX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(ZZ_pX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm // the return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b); inline ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& b) { ZZ_pX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) void PowerCompose(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F); inline ZZ_pX PowerCompose(const ZZ_pX& a, long d, const ZZ_pXModulus& F) { ZZ_pX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see ) NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/fileio.h0000644417616742025610000000220514064716022017654 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_fileio__H #define NTL_fileio__H #include #include #include #include NTL_OPEN_NNS class FileList { private: Vec< Vec > data; FileList(const FileList&); // disable void operator=(const FileList&); // disable public: FileList() { } void AddFile(const char *name); void RemoveLast(); ~FileList(); }; void OpenWrite(NTL_SNS ofstream& s, const char *name); // opens file for writing...aborts if fails void OpenWrite(NTL_SNS ofstream& s, const char *name, FileList& flist); // opens file for writing and adds name to flist void OpenRead(NTL_SNS ifstream& s, const char *name); // opens file for reading void CloseWrite(NTL_SNS ofstream& s); // closes s, checks for failure const char *FileName(const char* stem, long d); // builds the name from stem-DDDDD, returns pointer to buffer const NTL_SNS string& UniqueID(); // ideally, a unique ID (across all processes and threads), // but it may not be perfect (useful for generating unique // file names and seeding PRG). NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lip.h0000644417616742025610000004555014064716022017203 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_g_lip__H #define NTL_g_lip__H #include #ifdef NTL_GMP_LIP #include #endif /* * This way of defining the bigint handle type is a bit non-standard, * but better for debugging. */ struct _ntl_gbigint_body { long alloc_; long size_; }; typedef _ntl_gbigint_body *_ntl_gbigint; #ifdef NTL_GMP_LIP #if (defined(NTL_HAVE_LL_TYPE) && !defined(NTL_LEGACY_SP_MULMOD)) #define NTL_LONGLONG_SP_MULMOD // on 64 bit machines, hold NTL_SP_NBITS to 60 bits, // as certain operations (in particular, TBL_REM in g_lip_impl.h) // are a bit faster #if (!defined(NTL_MAXIMIZE_SP_NBITS) && NTL_BITS_PER_LONG >= 64) #define NTL_SP_NBITS (NTL_BITS_PER_LONG-4) #else #define NTL_SP_NBITS (NTL_BITS_PER_LONG-2) #endif #if (defined(NTL_ENABLE_AVX_FFT) && (NTL_SP_NBITS > 50)) #undef NTL_SP_NBITS #define NTL_SP_NBITS (50) #endif #elif (NTL_LONGDOUBLE_OK && !defined(NTL_LEGACY_SP_MULMOD) && !defined(NTL_DISABLE_LONGDOUBLE) && !defined(NTL_ENABLE_AVX_FFT)) #define NTL_LONGDOUBLE_SP_MULMOD #define NTL_SP_NBITS NTL_WNBITS_MAX // on 64 bit machines, hold NTL_SP_NBITS to 60 bits (see above) #if (!defined(NTL_MAXIMIZE_SP_NBITS) && NTL_BITS_PER_LONG >= 64 && NTL_SP_NBITS > NTL_BITS_PER_LONG-4) #undef NTL_SP_NBITS #define NTL_SP_NBITS (NTL_BITS_PER_LONG-4) #endif #else #define NTL_SP_NBITS NTL_NBITS_MAX #endif #if (NTL_SP_NBITS > NTL_ZZ_NBITS) // if nails, we need to ensure NTL_SP_NBITS does not exceed // NTL_ZZ_NBITS #undef NTL_SP_NBITS #define NTL_SP_NBITS NTL_ZZ_NBITS #endif #define NTL_NSP_NBITS NTL_NBITS_MAX #if (NTL_NSP_NBITS > NTL_SP_NBITS) #undef NTL_NSP_NBITS #define NTL_NSP_NBITS NTL_SP_NBITS #endif #define NTL_WSP_NBITS (NTL_BITS_PER_LONG-2) #if (NTL_WSP_NBITS > NTL_ZZ_NBITS) // if nails, we need to ensure NTL_WSP_NBITS does not exceed // NTL_ZZ_NBITS #undef NTL_WSP_NBITS #define NTL_WSP_NBITS NTL_ZZ_NBITS #endif #define NTL_SP_BOUND (1L << NTL_SP_NBITS) #define NTL_NSP_BOUND (1L << NTL_NSP_NBITS) #define NTL_WSP_BOUND (1L << NTL_WSP_NBITS) /* define the following so an error is raised */ #define NTL_RADIX ...... #define NTL_NBITSH ...... #define NTL_RADIXM ...... #define NTL_RADIXROOT ...... #define NTL_RADIXROOTM ...... #define NTL_FRADIX_INV ...... #else #define NTL_NBITS NTL_NBITS_MAX #define NTL_RADIX (1L<>1) #define NTL_RADIXM (NTL_RADIX-1) #define NTL_RADIXROOT (1L<= 30, as the documentation // guarantees this. This should only be a problem if GMP // uses some really funny nail bits. #if (NTL_SP_NBITS < 30) #error "NTL_SP_NBITS too small" #endif // Second, check that NTL_BITS_PER_LONG-NTL_SP_NBITS == 2 or // NTL_BITS_PER_LONG-NTL_SP_NBITS >= 4. // Some code in sp_arith.h seems to rely on this assumption. // Again, this should only be a problem if GMP // uses some really funny nail bits. #if (NTL_BITS_PER_LONG-NTL_SP_NBITS != 2 && NTL_BITS_PER_LONG-NTL_SP_NBITS < 4) #error "NTL_SP_NBITS is invalid" #endif // DIRT: These are copied from lip.cpp file inline long& _ntl_ALLOC(_ntl_gbigint p) { return p->alloc_; } inline long& _ntl_SIZE(_ntl_gbigint p) { return p->size_; } inline long _ntl_ZEROP(_ntl_gbigint p) { return !p || !_ntl_SIZE(p); } inline long _ntl_PINNED(_ntl_gbigint p) { return p && (_ntl_ALLOC(p) & 1); } /*********************************************************************** Basic Functions ***********************************************************************/ void _ntl_gsadd(_ntl_gbigint a, long d, _ntl_gbigint *b); /* *b = a + d */ void _ntl_gssub(_ntl_gbigint a, long d, _ntl_gbigint *b); /* *b = a - d */ void _ntl_gadd(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a + b */ void _ntl_gsub(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a - b */ void _ntl_gsubpos(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a - b; assumes a >= b >= 0 */ void _ntl_gsmul(_ntl_gbigint a, long d, _ntl_gbigint *b); /* *b = d * a */ void _ntl_gmul(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* *c = a * b */ void _ntl_gsq(_ntl_gbigint a, _ntl_gbigint *c); /* *c = a * a */ long _ntl_gsdiv(_ntl_gbigint a, long b, _ntl_gbigint *q); /* (*q) = floor(a/b) and a - floor(a/b)*(*q) is returned; error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_gdiv(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *q, _ntl_gbigint *r); /* (*q) = floor(a/b) and (*r) = a - floor(a/b)*(*q); error is raised if b == 0; if b does not divide a, then sign(*q) == sign(b) */ void _ntl_gmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *r); /* same as _ntl_gdiv, but only remainder is computed */ long _ntl_gsmod(_ntl_gbigint a, long d); /* same as _ntl_gsdiv, but only remainder is computed */ void _ntl_gquickmod(_ntl_gbigint *r, _ntl_gbigint b); /* *r = *r % b; The division is performed in place (but may sometimes assumes b > 0 and *r >= 0; cause *r to grow by one digit) */ void _ntl_gsaddmul(_ntl_gbigint x, long y, _ntl_gbigint *ww); /* *ww += x*y */ void _ntl_gaddmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww); /* *ww += x*y */ void _ntl_gssubmul(_ntl_gbigint x, long y, _ntl_gbigint *ww); /* *ww -= x*y */ void _ntl_gsubmul(_ntl_gbigint x, _ntl_gbigint y, _ntl_gbigint *ww); /* *ww -= x*y */ /******************************************************************** Shifting and bit manipulation *********************************************************************/ void _ntl_glshift(_ntl_gbigint n, long k, _ntl_gbigint *a); /* *a = sign(n) * (|n| << k); shift is in reverse direction for negative k */ void _ntl_grshift(_ntl_gbigint n, long k, _ntl_gbigint *a); /* *a = sign(n) * (|n| >> k); shift is in reverse direction for negative k */ long _ntl_gmakeodd(_ntl_gbigint *n); /* if (n != 0) *n = m; return (k such that n == 2 ^ k * m with m odd); else return (0); */ long _ntl_gnumtwos(_ntl_gbigint n); /* return largest e such that 2^e divides n, or zero if n is zero */ long _ntl_godd(_ntl_gbigint a); /* returns 1 if n is odd and 0 if it is even */ long _ntl_gbit(_ntl_gbigint a, long p); /* returns p-th bit of a, where the low order bit is indexed by 0; p out of range returns 0 */ long _ntl_gsetbit(_ntl_gbigint *a, long p); /* returns original value of p-th bit of |a|, and replaces p-th bit of a by 1 if it was zero; error if p < 0 */ long _ntl_gswitchbit(_ntl_gbigint *a, long p); /* returns original value of p-th bit of |a|, and switches the value of p-th bit of a; p starts counting at 0; error if p < 0 */ void _ntl_glowbits(_ntl_gbigint a, long k, _ntl_gbigint *b); /* places k low order bits of |a| in b */ long _ntl_gslowbits(_ntl_gbigint a, long k); /* returns k low order bits of |a| */ long _ntl_gweights(long a); /* returns Hamming weight of |a| */ long _ntl_gweight(_ntl_gbigint a); /* returns Hamming weight of |a| */ void _ntl_gand(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` and `bits of |b|` */ void _ntl_gor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` inclusive or `bits of |b|` */ void _ntl_gxor(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* c gets bit pattern `bits of |a|` exclusive or `bits of |b|` */ /************************************************************************ Comparison *************************************************************************/ long _ntl_gcompare(_ntl_gbigint a, _ntl_gbigint b); /* if (a > b) return (1); if (a == b) return (0); if (a < b) return (-1); */ long _ntl_gscompare(_ntl_gbigint a, long b); /* single-precision version of the above */ inline long _ntl_giszero (_ntl_gbigint a) { return _ntl_ZEROP(a); } /* test for 0 */ inline long _ntl_gsign(_ntl_gbigint a) { long sa; if (!a) return 0; sa = _ntl_SIZE(a); if (sa > 0) return 1; if (sa == 0) return 0; return -1; } /* if (a > 0) return (1); if (a == 0) return (0); if (a < 0) return (-1); */ void _ntl_gabs(_ntl_gbigint *a); /* *a = |a| */ void _ntl_gnegate(_ntl_gbigint *a); /* *a = -a */ void _ntl_gcopy(_ntl_gbigint a, _ntl_gbigint *b); /* *b = a; */ void _ntl_gswap(_ntl_gbigint *a, _ntl_gbigint *b); /* swap a and b (by swaping pointers) */ long _ntl_g2log(_ntl_gbigint a); /* number of bits in |a|; returns 0 if a = 0 */ inline long _ntl_g2logs(long a) /* single-precision version of the above */ { unsigned long aa = a >= 0 ? a : - ((unsigned long) a); return _ntl_count_bits(aa); } /******************************************************************** Conversion *********************************************************************/ void _ntl_gzero(_ntl_gbigint *a); /* *a = 0; */ void _ntl_gone(_ntl_gbigint *a); /* *a = 1 */ void _ntl_gintoz(long d, _ntl_gbigint *a); /* *a = d; */ void _ntl_guintoz(unsigned long d, _ntl_gbigint *a); /* *a = d; space is allocated */ long _ntl_gtoint(_ntl_gbigint a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ unsigned long _ntl_gtouint(_ntl_gbigint a); /* converts a to a long; overflow results in value mod 2^{NTL_BITS_PER_LONG}. */ double _ntl_gdoub(_ntl_gbigint n); /* converts a to a double; no overflow check */ long _ntl_ground_correction(_ntl_gbigint a, long k, long residual); /* k >= 1, |a| >= 2^k, and residual is 0, 1, or -1. The result is what we should add to (a >> k) to round x = a/2^k to the nearest integer using IEEE-like rounding rules (i.e., round to nearest, and round to even to break ties). The result is either 0 or sign(a). If residual is not zero, it is as if x were replaced by x' = x + residual*2^{-(k+1)}. This can be used to break ties when x is exactly half way between two integers. */ double _ntl_glog(_ntl_gbigint a); /* computes log(a), protecting against overflow */ void _ntl_gdoubtoz(double a, _ntl_gbigint *x); /* x = floor(a); */ /************************************************************************ Square roots *************************************************************************/ long _ntl_gsqrts(long n); /* return floor(sqrt(n)); error raised in n < 0 */ void _ntl_gsqrt(_ntl_gbigint n, _ntl_gbigint *r); /* *r = floor(sqrt(n)); error raised in n < 0 */ /********************************************************************* Exponentiation **********************************************************************/ void _ntl_gexp(_ntl_gbigint a, long e, _ntl_gbigint *b); /* *b = a^e; error raised if e < 0 */ void _ntl_gexps(long a, long e, _ntl_gbigint *b); /* *b = a^e; error raised if e < 0 */ /********************************************************************* Modular Arithmetic Addition, subtraction, multiplication, squaring division, inversion, and exponentiation modulo a positive modulus n, where all operands (except for the exponent in exponentiation) and results are in the range [0, n-1]. ALIAS RESTRICTION: output parameters should not alias n ***********************************************************************/ void _ntl_gaddmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a + b) % n */ void _ntl_gsubmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a - b) % n */ void _ntl_gsmulmod(_ntl_gbigint a, long b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a * b) % n */ void _ntl_gmulmod(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a * b) % n */ void _ntl_gsqmod(_ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (a ^ 2) % n */ void _ntl_ginvmod(_ntl_gbigint a, _ntl_gbigint n, _ntl_gbigint *c); /* *c = (1 / a) % n; error raised if gcd(b, n) != 1 */ void _ntl_gpowermod(_ntl_gbigint g, _ntl_gbigint e, _ntl_gbigint F, _ntl_gbigint *h); /* *b = (a ^ e) % n; */ /************************************************************************** Euclidean Algorithms ***************************************************************************/ void _ntl_ggcd(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r); /* *r = greatest common divisor of m1 and m2; */ void _ntl_ggcd_alt(_ntl_gbigint m1, _ntl_gbigint m2, _ntl_gbigint *r); /* *r = greatest common divisor of m1 and m2; a simpler algorithm used for validation */ void _ntl_gexteucl(_ntl_gbigint a, _ntl_gbigint *xa, _ntl_gbigint b, _ntl_gbigint *xb, _ntl_gbigint *d); /* *d = a * *xa + b * *xb = gcd(a, b); sets *d, *xa and *xb given a and b; */ long _ntl_ginv(_ntl_gbigint a, _ntl_gbigint b, _ntl_gbigint *c); /* if (a and b coprime) { *c = inv; return(0); } else { *c = gcd(a, b); return(1); } where inv is such that (inv * a) == 1 mod b; error raised if a < 0 or b <= 0 */ long _ntl_gxxratrecon(_ntl_gbigint x, _ntl_gbigint m, _ntl_gbigint a_bound, _ntl_gbigint b_bound, _ntl_gbigint *a, _ntl_gbigint *b); /* rational reconstruction: see doc in ZZ.txt */ /********************************************************************** Storage Allocation These routines use malloc and free. ***********************************************************************/ inline long _ntl_gmaxalloc(_ntl_gbigint x) { if (!x) return 0; else return _ntl_ALLOC(x) >> 2; } // DIRT: see lip.c for more info on ALLOC void _ntl_gsetlength(_ntl_gbigint *v, long len); /* Allocates enough space to hold a len-digit number, where each digit has NTL_NBITS bits. If space must be allocated, space for one extra digit is always allocated. if (exact) then no rounding occurs. */ void _ntl_gfree(_ntl_gbigint x); /* Free's space held by x. */ /******************************************************************* Special routines ********************************************************************/ inline long _ntl_gsize(_ntl_gbigint rep) { if (!rep) return 0; else if (_ntl_SIZE(rep) < 0) return -_ntl_SIZE(rep); else return _ntl_SIZE(rep); } long _ntl_gisone(_ntl_gbigint n); long _ntl_gsptest(_ntl_gbigint a); long _ntl_gwsptest(_ntl_gbigint a); long _ntl_gcrtinrange(_ntl_gbigint g, _ntl_gbigint a); void _ntl_gfrombytes(_ntl_gbigint *x, const unsigned char *p, long n); void _ntl_gbytesfromz(unsigned char *p, _ntl_gbigint a, long nn); long _ntl_gblock_construct_alloc(_ntl_gbigint *x, long d, long n); void _ntl_gblock_construct_set(_ntl_gbigint x, _ntl_gbigint *y, long i); long _ntl_gblock_destroy(_ntl_gbigint x); long _ntl_gblock_storage(long d); // These are common to both implementations class _ntl_tmp_vec { public: virtual ~_ntl_tmp_vec() { } }; class _ntl_crt_struct { public: virtual ~_ntl_crt_struct() { } virtual bool special() = 0; virtual void insert(long i, _ntl_gbigint m) = 0; virtual _ntl_tmp_vec *extract() = 0; virtual _ntl_tmp_vec *fetch() = 0; virtual void eval(_ntl_gbigint *x, const long *b, _ntl_tmp_vec *tmp_vec) = 0; }; _ntl_crt_struct * _ntl_crt_struct_build(long n, _ntl_gbigint p, long (*primes)(long)); class _ntl_rem_struct { public: virtual ~_ntl_rem_struct() { } virtual void eval(long *x, _ntl_gbigint a, _ntl_tmp_vec *tmp_vec) = 0; virtual _ntl_tmp_vec *fetch() = 0; }; _ntl_rem_struct * _ntl_rem_struct_build(long n, _ntl_gbigint modulus, long (*p)(long)); // montgomery class _ntl_reduce_struct { public: virtual ~_ntl_reduce_struct() { } virtual void eval(_ntl_gbigint *x, _ntl_gbigint *a) = 0; virtual void adjust(_ntl_gbigint *x) = 0; }; _ntl_reduce_struct * _ntl_reduce_struct_build(_ntl_gbigint modulus, _ntl_gbigint excess); // faster reduction with preconditioning -- general usage, single modulus struct _ntl_general_rem_one_struct; _ntl_general_rem_one_struct * _ntl_general_rem_one_struct_build(long p); long _ntl_general_rem_one_struct_apply(_ntl_gbigint a, long p, _ntl_general_rem_one_struct *pinfo); void _ntl_general_rem_one_struct_delete(_ntl_general_rem_one_struct *pinfo); long _ntl_gvalidate(_ntl_gbigint a); // special-purpose routines for accumulating CRT-like summations void _ntl_quick_accum_begin(_ntl_gbigint *xp, long sz); void _ntl_quick_accum_muladd(_ntl_gbigint x, _ntl_gbigint y, long b); void _ntl_quick_accum_end(_ntl_gbigint x); // special-purpose routines for SSMul in ZZX #if (defined(NTL_GMP_LIP) && (NTL_ZZ_NBITS & (NTL_ZZ_NBITS-1)) == 0) // NOTE: the test (NTL_ZZ_NBITS & (NTL_ZZ_NBITS-1)) == 0 // effectively checks that NTL_ZZ_NBITS is a power of two #define NTL_PROVIDES_SS_LIP_IMPL void _ntl_leftrotate(_ntl_gbigint *a, const _ntl_gbigint *b, long e, _ntl_gbigint p, long n, _ntl_gbigint *scratch); void _ntl_ss_addmod(_ntl_gbigint *x, const _ntl_gbigint *a, const _ntl_gbigint *b, _ntl_gbigint p, long n); void _ntl_ss_submod(_ntl_gbigint *x, const _ntl_gbigint *a, const _ntl_gbigint *b, _ntl_gbigint p, long n); #endif #endif ntl-11.5.1/include/NTL/lzz_p.h0000644417616742025610000003122314064716022017545 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_p__H #define NTL_zz_p__H #include #include #include #include NTL_OPEN_NNS class zz_pInfoT { private: zz_pInfoT(); // disabled zz_pInfoT(const zz_pInfoT&); // disabled void operator=(const zz_pInfoT&); // disabled public: zz_pInfoT(long NewP, long maxroot); zz_pInfoT(INIT_FFT_TYPE, FFTPrimeInfo *info); zz_pInfoT(INIT_USER_FFT_TYPE, long q); long p; mulmod_t pinv; sp_reduce_struct red_struct; sp_ll_reduce_struct ll_red_struct; sp_ZZ_reduce_struct ZZ_red_struct; FFTPrimeInfo* p_info; // non-null means we are directly using // an FFT prime UniquePtr p_info_owner; // for user-defined FFT primes, we store the corresponding // FFTPrimeInfo object here long PrimeCnt; // 0 for FFT prime; otherwise same as NumPrimes // used for establishing crossover points long NumPrimes; long MaxRoot; long MinusMModP; // -M mod p, M = product of primes mulmod_precon_t MinusMModPpinv; // the following arrays are indexed 0..NumPrimes-1 // q = FFTPrime[i] Vec CoeffModP; // coeff mod p Vec CoeffModPpinv; Vec x; // u/q, where u = (M/q)^{-1} mod q Vec u; // u, as above Vec uqinv; // MulModPrecon for u }; extern NTL_CHEAP_THREAD_LOCAL zz_pInfoT *zz_pInfo; // current modulus, initially null class zz_pContext { private: SmartPtr ptr; public: zz_pContext() { } // copy constructor, assignment, destructor: default explicit zz_pContext(long p, long maxroot=NTL_FFTMaxRoot); zz_pContext(INIT_FFT_TYPE, long index); zz_pContext(INIT_USER_FFT_TYPE, long q); void save(); void restore() const; // some hooks that are useful in helib and elsewhere // FIXME: generalize these to other context classes // and document bool null() const { return ptr == 0; } bool equals(const zz_pContext& other) const { return ptr == other.ptr; } long modulus() const { return ptr->p; } mulmod_t ModulusInverse() const { return ptr->pinv; } const sp_ZZ_reduce_struct& ZZ_red_struct() const { return ptr->ZZ_red_struct; } sp_reduce_struct red_struct() const { return ptr->red_struct; } }; // should be in FFT.h, but because of some weirdess involving NTL_WIZARD_HACK, // it has to be here inline const sp_ZZ_reduce_struct& GetFFT_ZZ_red_struct(long i) { return FFTTables[i]->zz_p_context->ZZ_red_struct; } class zz_pBak { private: zz_pContext c; bool MustRestore; zz_pBak(const zz_pBak&); // disabled void operator=(const zz_pBak&); // disabled public: void save(); void restore(); zz_pBak() : MustRestore(false) { } ~zz_pBak(); }; class zz_pPush { private: zz_pBak bak; zz_pPush(const zz_pPush&); // disabled void operator=(const zz_pPush&); // disabled public: zz_pPush() { bak.save(); } explicit zz_pPush(const zz_pContext& context) { bak.save(); context.restore(); } explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot) { bak.save(); zz_pContext c(p, maxroot); c.restore(); } zz_pPush(INIT_FFT_TYPE, long index) { bak.save(); zz_pContext c(INIT_FFT, index); c.restore(); } zz_pPush(INIT_USER_FFT_TYPE, long q) { bak.save(); zz_pContext c(INIT_USER_FFT, q); c.restore(); } }; #define NTL_zz_pRegister(x) zz_p x class zz_pX; // forward declaration class zz_p { public: typedef long rep_type; typedef zz_pContext context_type; typedef zz_pBak bak_type; typedef zz_pPush push_type; typedef zz_pX poly_type; long _zz_p__rep; static void init(long NewP, long maxroot=NTL_FFTMaxRoot); static void FFTInit(long index); static void UserFFTInit(long q); // ****** constructors and assignment zz_p() : _zz_p__rep(0) { } explicit zz_p(long a) : _zz_p__rep(0) { *this = a; } zz_p(const zz_p& a) : _zz_p__rep(a._zz_p__rep) { } zz_p& operator=(const zz_p& a) { _zz_p__rep = a._zz_p__rep; return *this; } inline zz_p& operator=(long a); // a loop-hole for direct access to _zz_p__rep long& LoopHole() { return _zz_p__rep; } static long modulus() { return zz_pInfo->p; } static zz_p zero() { return zz_p(); } static mulmod_t ModulusInverse() { return zz_pInfo->pinv; } static sp_reduce_struct red_struct() { return zz_pInfo->red_struct; } static sp_ll_reduce_struct ll_red_struct() { return zz_pInfo->ll_red_struct; } static const sp_ZZ_reduce_struct& ZZ_red_struct() { return zz_pInfo->ZZ_red_struct; } static long PrimeCnt() { return zz_pInfo->PrimeCnt; } static long storage() { return sizeof(long); } static bool IsFFTPrime() { return zz_pInfo->p_info != 0; } zz_p(long a, INIT_LOOP_HOLE_TYPE) { _zz_p__rep = a; } // for consistency zz_p(INIT_NO_ALLOC_TYPE) : _zz_p__rep(0) { } zz_p(INIT_ALLOC_TYPE) : _zz_p__rep(0) { } void allocate() { } }; NTL_DECLARE_RELOCATABLE((zz_p*)) inline zz_p to_zz_p(long a) { return zz_p(rem(a, zz_pInfo->p, zz_pInfo->red_struct), INIT_LOOP_HOLE); } inline void conv(zz_p& x, long a) { x._zz_p__rep = rem(a, zz_pInfo->p, zz_pInfo->red_struct); } inline void VectorConv(long k, zz_p *x, const long *a) { if (k <= 0) return; sp_reduce_struct red_struct = zz_p::red_struct(); long p = zz_p::modulus(); for (long i = 0; i < k; i++) x[i].LoopHole() = rem(a[i], p, red_struct); } inline zz_p& zz_p::operator=(long a) { conv(*this, a); return *this; } inline zz_p to_zz_p(const ZZ& a) { return zz_p(zz_p::ZZ_red_struct().rem(a), INIT_LOOP_HOLE); } inline void conv(zz_p& x, const ZZ& a) { x._zz_p__rep = zz_p::ZZ_red_struct().rem(a); } inline void VectorConv(long k, zz_p *x, const ZZ *a) { if (k <= 0) return; const sp_ZZ_reduce_struct& ZZ_red_struct = zz_p::ZZ_red_struct(); for (long i = 0; i < k; i++) x[i].LoopHole() = ZZ_red_struct.rem(a[i]); } // read-only access to _zz_p__representation inline long rep(zz_p a) { return a._zz_p__rep; } inline void clear(zz_p& x) // x = 0 { x._zz_p__rep = 0; } inline void set(zz_p& x) // x = 1 { x._zz_p__rep = 1; } inline void swap(zz_p& x, zz_p& y) // swap x and y { long t; t = x._zz_p__rep; x._zz_p__rep = y._zz_p__rep; y._zz_p__rep = t; } // ****** addition inline void add(zz_p& x, zz_p a, zz_p b) // x = a + b { x._zz_p__rep = AddMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus()); } inline void sub(zz_p& x, zz_p a, zz_p b) // x = a - b { x._zz_p__rep = SubMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus()); } inline void negate(zz_p& x, zz_p a) // x = -a { x._zz_p__rep = SubMod(0, a._zz_p__rep, zz_p::modulus()); } // scalar versions inline void add(zz_p& x, zz_p a, long b) { add(x, a, to_zz_p(b)); } inline void add(zz_p& x, long a, zz_p b) { add(x, to_zz_p(a), b); } inline void sub(zz_p& x, zz_p a, long b) { sub(x, a, to_zz_p(b)); } inline void sub(zz_p& x, long a, zz_p b) { sub(x, to_zz_p(a), b); } inline zz_p operator+(zz_p a, zz_p b) { zz_p x; add(x, a, b); return x; } inline zz_p operator+(zz_p a, long b) { zz_p x; add(x, a, b); return x; } inline zz_p operator+(long a, zz_p b) { zz_p x; add(x, a, b); return x; } inline zz_p operator-(zz_p a, zz_p b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(zz_p a, long b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(long a, zz_p b) { zz_p x; sub(x, a, b); return x; } inline zz_p operator-(zz_p a) { zz_p x; negate(x, a); return x; } inline zz_p& operator+=(zz_p& x, zz_p b) { add(x, x, b); return x; } inline zz_p& operator+=(zz_p& x, long b) { add(x, x, b); return x; } inline zz_p& operator-=(zz_p& x, zz_p b) { sub(x, x, b); return x; } inline zz_p& operator-=(zz_p& x, long b) { sub(x, x, b); return x; } inline zz_p& operator++(zz_p& x) { add(x, x, 1); return x; } inline void operator++(zz_p& x, int) { add(x, x, 1); } inline zz_p& operator--(zz_p& x) { sub(x, x, 1); return x; } inline void operator--(zz_p& x, int) { sub(x, x, 1); } // ****** multiplication inline void mul(zz_p& x, zz_p a, zz_p b) // x = a*b { x._zz_p__rep = MulMod(a._zz_p__rep, b._zz_p__rep, zz_p::modulus(), zz_p::ModulusInverse()); } inline void mul(zz_p& x, zz_p a, long b) { mul(x, a, to_zz_p(b)); } inline void mul(zz_p& x, long a, zz_p b) { mul(x, to_zz_p(a), b); } inline zz_p operator*(zz_p a, zz_p b) { zz_p x; mul(x, a, b); return x; } inline zz_p operator*(zz_p a, long b) { zz_p x; mul(x, a, b); return x; } inline zz_p operator*(long a, zz_p b) { zz_p x; mul(x, a, b); return x; } inline zz_p& operator*=(zz_p& x, zz_p b) { mul(x, x, b); return x; } inline zz_p& operator*=(zz_p& x, long b) { mul(x, x, b); return x; } inline void sqr(zz_p& x, zz_p a) // x = a^2 { x._zz_p__rep = MulMod(a._zz_p__rep, a._zz_p__rep, zz_p::modulus(), zz_p::ModulusInverse()); } inline zz_p sqr(zz_p a) { zz_p x; sqr(x, a); return x; } // ****** division inline void div(zz_p& x, zz_p a, zz_p b) // x = a/b { x._zz_p__rep = MulMod(a._zz_p__rep, InvMod(b._zz_p__rep, zz_p::modulus()), zz_p::modulus(), zz_p::ModulusInverse()); } inline void inv(zz_p& x, zz_p a) // x = 1/a { x._zz_p__rep = InvMod(a._zz_p__rep, zz_p::modulus()); } inline zz_p inv(zz_p a) { zz_p x; inv(x, a); return x; } inline void div(zz_p& x, zz_p a, long b) { div(x, a, to_zz_p(b)); } inline void div(zz_p& x, long a, zz_p b) { div(x, to_zz_p(a), b); } inline zz_p operator/(zz_p a, zz_p b) { zz_p x; div(x, a, b); return x; } inline zz_p operator/(zz_p a, long b) { zz_p x; div(x, a, b); return x; } inline zz_p operator/(long a, zz_p b) { zz_p x; div(x, a, b); return x; } inline zz_p& operator/=(zz_p& x, zz_p b) { div(x, x, b); return x; } inline zz_p& operator/=(zz_p& x, long b) { div(x, x, b); return x; } // ****** exponentiation inline void power(zz_p& x, zz_p a, long e) // x = a^e { x._zz_p__rep = PowerMod(a._zz_p__rep, e, zz_p::modulus()); } inline zz_p power(zz_p a, long e) { zz_p x; power(x, a, e); return x; } // ****** comparison inline long IsZero(zz_p a) { return a._zz_p__rep == 0; } inline long IsOne(zz_p a) { return a._zz_p__rep == 1; } inline long operator==(zz_p a, zz_p b) { return a._zz_p__rep == b._zz_p__rep; } inline long operator!=(zz_p a, zz_p b) { return !(a == b); } inline long operator==(zz_p a, long b) { return a == to_zz_p(b); } inline long operator==(long a, zz_p b) { return to_zz_p(a) == b; } inline long operator!=(zz_p a, long b) { return !(a == b); } inline long operator!=(long a, zz_p b) { return !(a == b); } // ****** random numbers inline void random(zz_p& x) // x = random element in zz_p { x._zz_p__rep = RandomBnd(zz_p::modulus()); } inline zz_p random_zz_p() { zz_p x; random(x); return x; } inline void VectorRandom(long k, zz_p* x) { if (k <= 0) return; RandomBndGenerator gen(zz_p::modulus()); for (long i = 0; i < k; i++) x[i].LoopHole() = gen.next(); } // ****** input/output NTL_SNS ostream& operator<<(NTL_SNS ostream& s, zz_p a); NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_p& x); void conv(Vec& x, const Vec& a); void conv(Vec& x, const Vec& a); // explicit instantiation of more efficient versions, // defined in vec_lzz_p.c /* additional legacy conversions for v6 conversion regime */ inline void conv(int& x, zz_p a) { conv(x, rep(a)); } inline void conv(unsigned int& x, zz_p a) { conv(x, rep(a)); } inline void conv(long& x, zz_p a) { conv(x, rep(a)); } inline void conv(unsigned long& x, zz_p a) { conv(x, rep(a)); } inline void conv(ZZ& x, zz_p a) { conv(x, rep(a)); } inline void conv(zz_p& x, zz_p a) { x = a; } /* ------------------------------------- */ // ********************************************************* // *** specialized inner-product routines, for internal consumption // ********************************************************* #ifdef NTL_HAVE_LL_TYPE long InnerProd_LL(const long *ap, const zz_p *bp, long n, long d, sp_ll_reduce_struct dinv); long InnerProd_LL(const zz_p *ap, const zz_p *bp, long n, long d, sp_ll_reduce_struct dinv); inline bool InnerProd_L_viable(long n, long d) { if (n < 2) n = 2; // this ensures cast_unsigned(-1)/d^2 is at least 2, which // streamlines things if (n > 128) n = 128; return cast_unsigned(n) <= cast_unsigned(-1L)/cast_unsigned(d) && cast_unsigned(n)*cast_unsigned(d) <= cast_unsigned(-1L)/cast_unsigned(d); } inline long InnerProd_L_bound(long d) { return cast_unsigned(-1L)/(cast_unsigned(d)*cast_unsigned(d)); // This calculation ensures that the return value does not sign-overflow, // and that InnerProd_L itself can accumulate an extra term. } long InnerProd_L(const long *ap, const zz_p *bp, long n, long d, sp_reduce_struct dinv, long bound); long InnerProd_L(const zz_p *ap, const zz_p *bp, long n, long d, sp_reduce_struct dinv, long bound); #endif NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lzz_pE.h0000644417616742025610000003003314064716022017650 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_pE__H #define NTL_zz_pE__H #include #include #include #include NTL_OPEN_NNS class zz_pEInfoT { private: zz_pEInfoT(); // disabled zz_pEInfoT(const zz_pEInfoT&); // disabled void operator=(const zz_pEInfoT&); // disabled public: zz_pEInfoT(const zz_pX&); zz_pXModulus p; long _card_base; long _card_exp; Lazy _card; }; extern NTL_CHEAP_THREAD_LOCAL zz_pEInfoT *zz_pEInfo; // info for current modulus, initially null // fast TLS access class zz_pEContext { private: SmartPtr ptr; public: zz_pEContext() { } explicit zz_pEContext(const zz_pX& p) : ptr(MakeSmart(p)) { } // copy constructor, assignment, destructor: default void save(); void restore() const; }; class zz_pEBak { private: zz_pEContext c; bool MustRestore; zz_pEBak(const zz_pEBak&); // disabled void operator=(const zz_pEBak&); // disabled public: void save(); void restore(); zz_pEBak() : MustRestore(false) { } ~zz_pEBak(); }; class zz_pEPush { private: zz_pEBak bak; zz_pEPush(const zz_pEPush&); // disabled void operator=(const zz_pEPush&); // disabled public: zz_pEPush() { bak.save(); } explicit zz_pEPush(const zz_pEContext& context) { bak.save(); context.restore(); } explicit zz_pEPush(const zz_pX& p) { bak.save(); zz_pEContext c(p); c.restore(); } }; class zz_pEX; // forward declaration class zz_pE { public: typedef zz_pX rep_type; typedef zz_pEContext context_type; typedef zz_pEBak bak_type; typedef zz_pEPush push_type; typedef zz_pEX poly_type; zz_pX _zz_pE__rep; static long DivCross() { return 16; } static long ModCross() { return 8; } // ****** constructors and assignment zz_pE() { } // NO_ALLOC explicit zz_pE(long a) { *this = a; } // NO_ALLOC explicit zz_pE(const zz_p& a) { *this = a; } // NO_ALLOC zz_pE(INIT_NO_ALLOC_TYPE) { } // allocates no space zz_pE(INIT_ALLOC_TYPE) { _zz_pE__rep.rep.SetMaxLength(zz_pE::degree()); } // allocates space void allocate() { _zz_pE__rep.rep.SetMaxLength(zz_pE::degree()); } zz_pE(zz_pE& x, INIT_TRANS_TYPE) : _zz_pE__rep(x._zz_pE__rep, INIT_TRANS) { } // You can always access the _zz_pE__representation directly...if you dare. zz_pX& LoopHole() { return _zz_pE__rep; } void swap(zz_pE& x) { _zz_pE__rep.swap(x._zz_pE__rep); } static const zz_pXModulus& modulus() { return zz_pEInfo->p; } static long degree() { return deg(zz_pEInfo->p); } static const ZZ& cardinality(); static const zz_pE& zero(); static long initialized() { return (zz_pEInfo != 0); } static void init(const zz_pX&); inline zz_pE& operator=(long a); inline zz_pE& operator=(const zz_p& a); }; NTL_DECLARE_RELOCATABLE((zz_pE*)) inline const zz_pX& _zz_pE__rep(const zz_pE& a) { return a._zz_pE__rep; } inline void clear(zz_pE& x) // x = 0 { clear(x._zz_pE__rep); } inline void set(zz_pE& x) // x = 1 { set(x._zz_pE__rep); } inline void swap(zz_pE& x, zz_pE& y) // swap x and y { x.swap(y); } // ****** addition inline void add(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a + b { add(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a - b { sub(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep); } inline void negate(zz_pE& x, const zz_pE& a) { negate(x._zz_pE__rep, a._zz_pE__rep); } inline void add(zz_pE& x, const zz_pE& a, long b) { add(x._zz_pE__rep, a._zz_pE__rep, b); } inline void add(zz_pE& x, const zz_pE& a, const zz_p& b) { add(x._zz_pE__rep, a._zz_pE__rep, b); } inline void add(zz_pE& x, long a, const zz_pE& b) { add(x._zz_pE__rep, a, b._zz_pE__rep); } inline void add(zz_pE& x, const zz_p& a, const zz_pE& b) { add(x._zz_pE__rep, a, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_pE& a, long b) { sub(x._zz_pE__rep, a._zz_pE__rep, b); } inline void sub(zz_pE& x, const zz_pE& a, const zz_p& b) { sub(x._zz_pE__rep, a._zz_pE__rep, b); } inline void sub(zz_pE& x, long a, const zz_pE& b) { sub(x._zz_pE__rep, a, b._zz_pE__rep); } inline void sub(zz_pE& x, const zz_p& a, const zz_pE& b) { sub(x._zz_pE__rep, a, b._zz_pE__rep); } // ****** multiplication inline void mul(zz_pE& x, const zz_pE& a, const zz_pE& b) // x = a*b { MulMod(x._zz_pE__rep, a._zz_pE__rep, b._zz_pE__rep, zz_pE::modulus()); } inline void sqr(zz_pE& x, const zz_pE& a) // x = a^2 { SqrMod(x._zz_pE__rep, a._zz_pE__rep, zz_pE::modulus()); } inline zz_pE sqr(const zz_pE& a) { zz_pE x; sqr(x, a); NTL_OPT_RETURN(zz_pE, x); } inline void mul(zz_pE& x, const zz_pE& a, long b) { mul(x._zz_pE__rep, a._zz_pE__rep, b); } inline void mul(zz_pE& x, const zz_pE& a, const zz_p& b) { mul(x._zz_pE__rep, a._zz_pE__rep, b); } inline void mul(zz_pE& x, long a, const zz_pE& b) { mul(x._zz_pE__rep, a, b._zz_pE__rep); } inline void mul(zz_pE& x, const zz_p& a, const zz_pE& b) { mul(x._zz_pE__rep, a, b._zz_pE__rep); } // ****** division void div(zz_pE& x, const zz_pE& a, const zz_pE& b); void div(zz_pE& x, const zz_pE& a, long b); void div(zz_pE& x, const zz_pE& a, const zz_p& b); void div(zz_pE& x, long a, const zz_pE& b); void div(zz_pE& x, const zz_p& a, const zz_pE& b); void inv(zz_pE& x, const zz_pE& a); inline zz_pE inv(const zz_pE& a) { zz_pE x; inv(x, a); NTL_OPT_RETURN(zz_pE, x); } // ****** exponentiation inline void power(zz_pE& x, const zz_pE& a, const ZZ& e) // x = a^e { PowerMod(x._zz_pE__rep, a._zz_pE__rep, e, zz_pE::modulus()); } inline zz_pE power(const zz_pE& a, const ZZ& e) { zz_pE x; power(x, a, e); NTL_OPT_RETURN(zz_pE, x); } inline void power(zz_pE& x, const zz_pE& a, long e) { power(x, a, ZZ_expo(e)); } inline zz_pE power(const zz_pE& a, long e) { zz_pE x; power(x, a, e); NTL_OPT_RETURN(zz_pE, x); } // ****** conversion inline void conv(zz_pE& x, const zz_pX& a) { rem(x._zz_pE__rep, a, zz_pE::modulus()); } inline void conv(zz_pE& x, long a) { conv(x._zz_pE__rep, a); } inline void conv(zz_pE& x, const zz_p& a) { conv(x._zz_pE__rep, a); } inline void conv(zz_pE& x, const ZZ& a) { conv(x._zz_pE__rep, a); } inline zz_pE to_zz_pE(const zz_pX& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(long a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(const zz_p& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE to_zz_pE(const ZZ& a) { zz_pE x; conv(x, a); NTL_OPT_RETURN(zz_pE, x); } // ****** comparison inline long IsZero(const zz_pE& a) { return IsZero(a._zz_pE__rep); } inline long IsOne(const zz_pE& a) { return IsOne(a._zz_pE__rep); } inline long operator==(const zz_pE& a, const zz_pE& b) { return a._zz_pE__rep == b._zz_pE__rep; } inline long operator==(const zz_pE& a, long b) { return a._zz_pE__rep == b; } inline long operator==(const zz_pE& a, const zz_p& b) { return a._zz_pE__rep == b; } inline long operator==(long a, const zz_pE& b) { return a == b._zz_pE__rep; } inline long operator==(const zz_p& a, const zz_pE& b) { return a == b._zz_pE__rep; } inline long operator!=(const zz_pE& a, const zz_pE& b) { return !(a == b); } inline long operator!=(const zz_pE& a, long b) { return !(a == b); } inline long operator!=(const zz_pE& a, const zz_p& b) { return !(a == b); } inline long operator!=(long a, const zz_pE& b) { return !(a == b); } inline long operator!=(const zz_p& a, const zz_pE& b) { return !(a == b); } // ****** norm and trace inline void trace(zz_p& x, const zz_pE& a) { TraceMod(x, a._zz_pE__rep, zz_pE::modulus()); } inline zz_p trace(const zz_pE& a) { return TraceMod(a._zz_pE__rep, zz_pE::modulus()); } inline void norm(zz_p& x, const zz_pE& a) { NormMod(x, a._zz_pE__rep, zz_pE::modulus()); } inline zz_p norm(const zz_pE& a) { return NormMod(a._zz_pE__rep, zz_pE::modulus()); } // ****** random numbers inline void random(zz_pE& x) // x = random element in zz_pE { random(x._zz_pE__rep, zz_pE::degree()); } inline zz_pE random_zz_pE() { zz_pE x; random(x); NTL_OPT_RETURN(zz_pE, x); } // ****** input/output inline NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pE& a) { return s << a._zz_pE__rep; } NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pE& x); inline const zz_pX& rep(const zz_pE& a) { return a._zz_pE__rep; } inline zz_pE& zz_pE::operator=(long a) { conv(*this, a); return *this; } inline zz_pE& zz_pE::operator=(const zz_p& a) { conv(*this, a); return *this; } inline zz_pE operator+(const zz_pE& a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_pE& a, const zz_p& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_pE& a, long b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(const zz_p& a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator+(long a, const zz_pE& b) { zz_pE x; add(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, const zz_p& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a, long b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_p& a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(long a, const zz_pE& b) { zz_pE x; sub(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator-(const zz_pE& a) { zz_pE x; negate(x, a); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator+=(zz_pE& x, const zz_pE& b) { add(x, x, b); return x; } inline zz_pE& operator+=(zz_pE& x, const zz_p& b) { add(x, x, b); return x; } inline zz_pE& operator+=(zz_pE& x, long b) { add(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, const zz_pE& b) { sub(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, const zz_p& b) { sub(x, x, b); return x; } inline zz_pE& operator-=(zz_pE& x, long b) { sub(x, x, b); return x; } inline zz_pE& operator++(zz_pE& x) { add(x, x, 1); return x; } inline void operator++(zz_pE& x, int) { add(x, x, 1); } inline zz_pE& operator--(zz_pE& x) { sub(x, x, 1); return x; } inline void operator--(zz_pE& x, int) { sub(x, x, 1); } inline zz_pE operator*(const zz_pE& a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_pE& a, const zz_p& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_pE& a, long b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(const zz_p& a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator*(long a, const zz_pE& b) { zz_pE x; mul(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator*=(zz_pE& x, const zz_pE& b) { mul(x, x, b); return x; } inline zz_pE& operator*=(zz_pE& x, const zz_p& b) { mul(x, x, b); return x; } inline zz_pE& operator*=(zz_pE& x, long b) { mul(x, x, b); return x; } inline zz_pE operator/(const zz_pE& a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_pE& a, const zz_p& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_pE& a, long b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(const zz_p& a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE operator/(long a, const zz_pE& b) { zz_pE x; div(x, a, b); NTL_OPT_RETURN(zz_pE, x); } inline zz_pE& operator/=(zz_pE& x, const zz_pE& b) { div(x, x, b); return x; } inline zz_pE& operator/=(zz_pE& x, const zz_p& b) { div(x, x, b); return x; } inline zz_pE& operator/=(zz_pE& x, long b) { div(x, x, b); return x; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pX& x, const zz_pE& a) { x = rep(a); } inline void conv(zz_pE& x, const zz_pE& a) { x = a; } /* ------------------------------------- */ NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lzz_pEX.h0000644417616742025610000007546114064716022020016 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_pEX__H #define NTL_zz_pEX__H #include #include NTL_OPEN_NNS class zz_pEXModulus; // forward declaration class zz_pEX { public: typedef zz_pE coeff_type; typedef zz_pEXModulus modulus_type; vec_zz_pE rep; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ zz_pEX() { } // initial value 0 // default copy constructor and assignment // default destructor explicit zz_pEX(long a) { *this = a; } explicit zz_pEX(const zz_p& a) { *this = a; } explicit zz_pEX(const zz_pE& a) { *this = a; } zz_pEX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void swap(zz_pEX& x) { rep.swap(x.rep); } void SetLength(long n) { rep.SetLength(n); } zz_pE& operator[](long i) { return rep[i]; } const zz_pE& operator[](long i) const { return rep[i]; } static const zz_pEX& zero(); inline zz_pEX(long i, const zz_pE& c); inline zz_pEX(long i, const zz_p& c); inline zz_pEX(long i, long c); inline zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c); inline zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c); inline zz_pEX(INIT_MONO_TYPE, long i, long c); inline zz_pEX(INIT_MONO_TYPE, long i); inline zz_pEX& operator=(long a); inline zz_pEX& operator=(const zz_p& a); inline zz_pEX& operator=(const zz_pE& a); zz_pEX(zz_pEX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; NTL_DECLARE_RELOCATABLE((zz_pEX*)) NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pEX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pEX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const zz_pEX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const zz_pE& coeff(const zz_pEX& a, long i); // zero if i not in range const zz_pE& LeadCoeff(const zz_pEX& a); // zero if a == 0 const zz_pE& ConstTerm(const zz_pEX& a); // zero if a == 0 void SetCoeff(zz_pEX& x, long i, const zz_pE& a); void SetCoeff(zz_pEX& x, long i, const zz_p& a); void SetCoeff(zz_pEX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pEX& x, long i); // x[i] = 1, error is raised if i < 0 inline zz_pEX::zz_pEX(long i, const zz_pE& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(long i, const zz_p& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(long i, long a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, const zz_p& a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline zz_pEX::zz_pEX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(zz_pEX& x); // x is set to the monomial X long IsX(const zz_pEX& a); // test if x = X inline void clear(zz_pEX& x) // x = 0 { x.rep.SetLength(0); } inline void set(zz_pEX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(zz_pEX& x, zz_pEX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void random(zz_pEX& x, long n); inline zz_pEX random_zz_pEX(long n) { zz_pEX x; random(x, n); NTL_OPT_RETURN(zz_pEX, x); } // generate a random polynomial of degree < n void trunc(zz_pEX& x, const zz_pEX& a, long m); inline zz_pEX trunc(const zz_pEX& a, long m) { zz_pEX x; trunc(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } // x = a % X^m void RightShift(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX RightShift(const zz_pEX& a, long n) { zz_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a/X^n void LeftShift(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX LeftShift(const zz_pEX& a, long n) { zz_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a*X^n #ifndef NTL_TRANSITION inline zz_pEX operator>>(const zz_pEX& a, long n) { zz_pEX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator<<(const zz_pEX& a, long n) { zz_pEX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator<<=(zz_pEX& x, long n) { LeftShift(x, x, n); return x; } inline zz_pEX& operator>>=(zz_pEX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(zz_pEX& x, const zz_pEX& a); inline zz_pEX diff(const zz_pEX& a) { zz_pEX x; diff(x, a); NTL_OPT_RETURN(zz_pEX, x); } // x = derivative of a void MakeMonic(zz_pEX& x); void reverse(zz_pEX& c, const zz_pEX& a, long hi); inline zz_pEX reverse(const zz_pEX& a, long hi) { zz_pEX x; reverse(x, a, hi); NTL_OPT_RETURN(zz_pEX, x); } inline void reverse(zz_pEX& c, const zz_pEX& a) { reverse(c, a, deg(a)); } inline zz_pEX reverse(const zz_pEX& a) { zz_pEX x; reverse(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_zz_pE VectorCopy(const zz_pEX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(zz_pEX& x, long a); void conv(zz_pEX& x, const ZZ& a); void conv(zz_pEX& x, const zz_p& a); void conv(zz_pEX& x, const zz_pX& a); void conv(zz_pEX& x, const zz_pE& a); void conv(zz_pEX& x, const vec_zz_pE& a); inline zz_pEX to_zz_pEX(long a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const ZZ& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_p& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_pX& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const zz_pE& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX to_zz_pEX(const vec_zz_pE& a) { zz_pEX x; conv(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& zz_pEX::operator=(long a) { conv(*this, a); return *this; } inline zz_pEX& zz_pEX::operator=(const zz_p& a) { conv(*this, a); return *this; } inline zz_pEX& zz_pEX::operator=(const zz_pE& a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pEX& x, const zz_pEX& a) { x = a; } inline void conv(vec_zz_pE& x, const zz_pEX& a) { x = a.rep; } class ZZX; void conv(zz_pEX& x, const ZZX& a); /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const zz_pEX& a); long IsOne(const zz_pEX& a); inline long operator==(const zz_pEX& a, const zz_pEX& b) { return a.rep == b.rep; } long operator==(const zz_pEX& a, long b); long operator==(const zz_pEX& a, const zz_p& b); long operator==(const zz_pEX& a, const zz_pE& b); inline long operator==(long a, const zz_pEX& b) { return (b == a); } inline long operator==(const zz_p& a, const zz_pEX& b) { return (b == a); } inline long operator==(const zz_pE& a, const zz_pEX& b) { return (b == a); } inline long operator!=(const zz_pEX& a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_pEX& a, long b) { return !(a == b); } inline long operator!=(const zz_pEX& a, const zz_p& b) { return !(a == b); } inline long operator!=(const zz_pEX& a, const zz_pE& b) { return !(a == b); } inline long operator!=(const long a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_p& a, const zz_pEX& b) { return !(a == b); } inline long operator!=(const zz_pE& a, const zz_pEX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); void negate(zz_pEX& x, const zz_pEX& a); // scalar versions void add(zz_pEX & x, const zz_pEX& a, long b); void add(zz_pEX & x, const zz_pEX& a, const zz_p& b); void add(zz_pEX & x, const zz_pEX& a, const zz_pE& b); inline void add(zz_pEX& x, const zz_pE& a, const zz_pEX& b) { add(x, b, a); } inline void add(zz_pEX& x, const zz_p& a, const zz_pEX& b) { add(x, b, a); } inline void add(zz_pEX& x, long a, const zz_pEX& b) { add(x, b, a); } void sub(zz_pEX & x, const zz_pEX& a, long b); void sub(zz_pEX & x, const zz_pEX& a, const zz_p& b); void sub(zz_pEX & x, const zz_pEX& a, const zz_pE& b); void sub(zz_pEX& x, const zz_pE& a, const zz_pEX& b); void sub(zz_pEX& x, const zz_p& a, const zz_pEX& b); void sub(zz_pEX& x, long a, const zz_pEX& b); inline zz_pEX operator+(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, const zz_pE& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, const zz_p& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pEX& a, long b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_pE& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(const zz_p& a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator+(long a, const zz_pEX& b) { zz_pEX x; add(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_pE& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, const zz_p& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pEX& a, long b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_pE& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(const zz_p& a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator-(long a, const zz_pEX& b) { zz_pEX x; sub(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator+=(zz_pEX& x, const zz_pEX& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, const zz_pE& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, const zz_p& b) { add(x, x, b); return x; } inline zz_pEX& operator+=(zz_pEX& x, long b) { add(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_pEX& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_pE& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, const zz_p& b) { sub(x, x, b); return x; } inline zz_pEX& operator-=(zz_pEX& x, long b) { sub(x, x, b); return x; } inline zz_pEX operator-(const zz_pEX& a) { zz_pEX x; negate(x, a); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator++(zz_pEX& x) { add(x, x, 1); return x; } inline void operator++(zz_pEX& x, int) { add(x, x, 1); } inline zz_pEX& operator--(zz_pEX& x) { sub(x, x, 1); return x; } inline void operator--(zz_pEX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b void sqr(zz_pEX& x, const zz_pEX& a); inline zz_pEX sqr(const zz_pEX& a) { zz_pEX x; sqr(x, a); NTL_OPT_RETURN(zz_pEX, x); } // x = a^2 void mul(zz_pEX & x, const zz_pEX& a, long b); void mul(zz_pEX & x, const zz_pEX& a, const zz_p& b); void mul(zz_pEX & x, const zz_pEX& a, const zz_pE& b); inline void mul(zz_pEX& x, long a, const zz_pEX& b) { mul(x, b, a); } inline void mul(zz_pEX& x, const zz_p& a, const zz_pEX& b) { mul(x, b, a); } inline void mul(zz_pEX& x, const zz_pE& a, const zz_pEX& b) { mul(x, b, a); } void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n); inline zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n) { zz_pEX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a * b % X^n void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n); inline zz_pEX SqrTrunc(const zz_pEX& a, long n) { zz_pEX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(zz_pEX, x); } // x = a*a % X^n inline zz_pEX operator*(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, const zz_pE& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, const zz_p& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pEX& a, long b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_pE& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(const zz_p& a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator*(long a, const zz_pEX& b) { zz_pEX x; mul(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator*=(zz_pEX& x, const zz_pEX& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, const zz_pE& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, const zz_p& b) { mul(x, x, b); return x; } inline zz_pEX& operator*=(zz_pEX& x, long b) { mul(x, x, b); return x; } void power(zz_pEX& x, const zz_pEX& a, long e); inline zz_pEX power(const zz_pEX& a, long e) { zz_pEX x; power(x, a, e); NTL_OPT_RETURN(zz_pEX, x); } /************************************************************* Division **************************************************************/ void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // q = a/b, r = a%b void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b); void div(zz_pEX& q, const zz_pEX& a, const zz_p& b); void div(zz_pEX& q, const zz_pEX& a, long b); // q = a/b void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // r = a%b long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(zz_pEX& x, const zz_pEX& a, long m); inline zz_pEX InvTrunc(const zz_pEX& a, long m) { zz_pEX x; InvTrunc(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } // computes x = a^{-1} % X^m // constant term must be invertible inline zz_pEX operator/(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, const zz_pE& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, const zz_p& b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator/(const zz_pEX& a, long b) { zz_pEX x; div(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator/=(zz_pEX& x, const zz_pEX& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, const zz_pE& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, const zz_p& b) { div(x, x, b); return x; } inline zz_pEX& operator/=(zz_pEX& x, long b) { div(x, x, b); return x; } inline zz_pEX operator%(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; rem(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator%=(zz_pEX& x, const zz_pEX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); inline zz_pEX GCD(const zz_pEX& a, const zz_pEX& b) { zz_pEX x; GCD(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b); // d = gcd(a,b), a s + b t = d /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the zz_pEXModulus data structure and associated routines below. void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); inline zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f) { zz_pEX x; MulMod(x, a, b, f); NTL_OPT_RETURN(zz_pEX, x); } // x = (a * b) % f void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; SqrMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = a^2 % f void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; MulByXMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = (a * X) mod f void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); inline zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f) { zz_pEX x; InvMod(x, a, f); NTL_OPT_RETURN(zz_pEX, x); } // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build zz_pEXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class zz_pEXModulus { public: zz_pEXModulus(); ~zz_pEXModulus(); zz_pEXModulus(const zz_pEX& ff); zz_pEX f; // the modulus operator const zz_pEX& () const { return f; } const zz_pEX& val() const { return f; } long n; // deg(f) long method; zz_pEX h0; zz_pE hlc; zz_pEX f0; OptionalVal< Lazy > tracevec; // extra level of indirection to ensure relocatability }; NTL_DECLARE_RELOCATABLE((zz_pEXModulus*)) inline long deg(const zz_pEXModulus& F) { return F.n; } void build(zz_pEXModulus& F, const zz_pEX& f); void rem(zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F); void MulMod(zz_pEX& c, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); inline zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F) { zz_pEX x; MulMod(x, a, b, F); NTL_OPT_RETURN(zz_pEX, x); } void SqrMod(zz_pEX& c, const zz_pEX& a, const zz_pEXModulus& F); inline zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; SqrMod(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } void PowerMod(zz_pEX& h, const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F); inline void PowerMod(zz_pEX& h, const zz_pEX& g, long e, const zz_pEXModulus& F) { PowerMod(h, g, ZZ_expo(e), F); } inline zz_pEX PowerMod(const zz_pEX& g, const ZZ& e, const zz_pEXModulus& F) { zz_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX PowerMod(const zz_pEX& g, long e, const zz_pEXModulus& F) { zz_pEX x; PowerMod(x, g, e, F); NTL_OPT_RETURN(zz_pEX, x); } void PowerXMod(zz_pEX& hh, const ZZ& e, const zz_pEXModulus& F); inline void PowerXMod(zz_pEX& h, long e, const zz_pEXModulus& F) { PowerXMod(h, ZZ_expo(e), F); } inline zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F) { zz_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX PowerXMod(long e, const zz_pEXModulus& F) { zz_pEX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; rem(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F) { rem(x, x, F); return x; } inline zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F) { zz_pEX x; div(x, a, F); NTL_OPT_RETURN(zz_pEX, x); } inline zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F) { div(x, x, F); return x; } /***************************************************************** vectors of zz_pEX's *****************************************************************/ typedef Vec vec_zz_pEX; /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a); inline zz_pEX BuildFromRoots(const vec_zz_pE& a) { zz_pEX x; BuildFromRoots(x, a); NTL_OPT_RETURN(zz_pEX, x); } // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a); inline zz_pE eval(const zz_pEX& f, const zz_pE& a) { zz_pE x; eval(x, f, a); NTL_OPT_RETURN(zz_pE, x); } // b = f(a) void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a); inline vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a) { vec_zz_pE x; eval(x, f, a); NTL_OPT_RETURN(vec_zz_pE, x); } // b[i] = f(a[i]) inline void eval(zz_pE& b, const zz_pX& f, const zz_pE& a) { conv(b, CompMod(f, rep(a), zz_pE::modulus())); } inline zz_pE eval(const zz_pX& f, const zz_pE& a) { zz_pE x; eval(x, f, a); NTL_OPT_RETURN(zz_pE, x); } // b = f(a) void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b); inline zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b) { zz_pEX x; interpolate(x, a, b); NTL_OPT_RETURN(zz_pEX, x); } // computes f such that f(a[i]) = b[i] /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); inline zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F) { zz_pEX x; CompMod(x, g, h, F); NTL_OPT_RETURN(zz_pEX, x); } // x = g(h) mod f void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If zz_pEXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If zz_pEXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, zz_pEXArgBound = 0. // If a single h is going to be used with many g's // then you should build a zz_pEXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If zz_pEXArgBound > 0, a table of size less than m may be built. struct zz_pEXArgument { vec_zz_pEX H; }; extern NTL_CHEAP_THREAD_LOCAL long zz_pEXArgBound; void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); inline zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F) { zz_pEX x; CompMod(x, g, H, F); NTL_OPT_RETURN(zz_pEX, x); } void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m); inline zz_pEX MinPolySeq(const vec_zz_pE& a, long m) { zz_pEX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(zz_pEX, x); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void MinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } void ProbMinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void ProbMinPolyMod(zz_pEX& hh, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); inline zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F) { zz_pEX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(zz_pEX, x); } void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pEX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pEX, x); } struct zz_pEXTransMultiplier { zz_pEX f0, fbi, b; long shamt, shamt_fbi, shamt_b; }; void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F); void TransMulMod(zz_pEX& x, const zz_pEX& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F); void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F); inline vec_zz_pE UpdateMap(const vec_zz_pE& a, const zz_pEXTransMultiplier& B, const zz_pEXModulus& F) { vec_zz_pE x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_zz_pE, x); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); inline vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F) { vec_zz_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_pE, x); } void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); inline vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEX& H, const zz_pEXModulus& F) { vec_zz_pE x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_pE, x); } inline void project(zz_pE& x, const vec_zz_pE& a, const zz_pEX& b) { InnerProduct(x, a, b.rep); } inline zz_pE project(const vec_zz_pE& a, const zz_pEX& b) { zz_pE x; InnerProduct(x, a, b.rep); NTL_OPT_RETURN(zz_pE, x); } /***************************************************************** modular composition and minimal polynonomials in towers ******************************************************************/ // composition void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F); inline zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& A, const zz_pEXModulus& F) { zz_pEX x; CompTower(x, g, A, F); NTL_OPT_RETURN(zz_pEX, x); } void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); inline zz_pEX CompTower(const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F) { zz_pEX x; CompTower(x, g, h, F); NTL_OPT_RETURN(zz_pEX, x); } // prob min poly void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; ProbMinPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { ProbMinPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; ProbMinPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // min poly void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; MinPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { MinPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; MinPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // irred poly void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); inline zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m) { zz_pX x; IrredPolyTower(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F) { IrredPolyTower(h, g, F, deg(F)*zz_pE::degree()); } inline zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F) { zz_pX x; IrredPolyTower(x, g, F); NTL_OPT_RETURN(zz_pX, x); } /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_zz_pE& S, const zz_pEX& f); inline vec_zz_pE TraceVec(const zz_pEX& f) { vec_zz_pE x; TraceVec(x, f); NTL_OPT_RETURN(vec_zz_pE, x); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F); inline zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F) { zz_pE x; TraceMod(x, a, F); NTL_OPT_RETURN(zz_pE, x); } void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); inline zz_pE TraceMod(const zz_pEX& a, const zz_pEX& f) { zz_pE x; TraceMod(x, a, f); NTL_OPT_RETURN(zz_pE, x); } void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); inline zz_pE NormMod(const zz_pEX& a, const zz_pEX& f) { zz_pE x; NormMod(x, a, f); NTL_OPT_RETURN(zz_pE, x); } void resultant(zz_pE& rres, const zz_pEX& a, const zz_pEX& b); inline zz_pE resultant(const zz_pEX& a, const zz_pEX& b) { zz_pE x; resultant(x, a, b); NTL_OPT_RETURN(zz_pE, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lzz_pEXFactoring.h0000644417616742025610000001241714064716022021643 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_pEXFactoring__H #define NTL_zz_pEXFactoring__H #include NTL_OPEN_NNS void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f); inline vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f) { vec_pair_zz_pEX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_zz_pE& x, const zz_pEX& f); inline vec_zz_pE FindRoots(const zz_pEX& f) { vec_zz_pE x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(zz_pE& root, const zz_pEX& f); inline zz_pE FindRoot(const zz_pEX& f) { zz_pE x; FindRoot(x, f); return x; } // finds a single root of f. // assumes that f is monic and splits into distinct linear factors extern NTL_CHEAP_THREAD_LOCAL long zz_pEX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF extern NTL_CHEAP_THREAD_LOCAL double zz_pEXFileThresh; // external files are used for baby/giant steps if size // of these tables exceeds zz_pEXFileThresh KB. void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose=0); inline vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h, long verbose=0) { vec_pair_zz_pEX_long x; NewDDF(x, f, h, verbose); return x; } void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& b, long d, long verbose=0); inline vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& b, long d, long verbose=0) { vec_zz_pEX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); inline vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0) { vec_zz_pEX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); inline vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0) { vec_zz_pEX x; SFCanZass(x, f, verbose); return x; } // Assumes f is monic and square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose=0); inline vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0) { vec_pair_zz_pEX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v); inline zz_pEX mul(const vec_pair_zz_pEX_long& v) { zz_pEX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const zz_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const zz_pEX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const zz_pEX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pEX& f, long n); inline zz_pEX BuildIrred_zz_pEX(long n) { zz_pEX x; BuildIrred(x, n); NTL_OPT_RETURN(zz_pEX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pEX& f, const zz_pEX& g); inline zz_pEX BuildRandomIrred(const zz_pEX& g) { zz_pEX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(zz_pEX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b); inline zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& b) { zz_pEX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pEX.h") void PowerCompose(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F); inline zz_pEX PowerCompose(const zz_pEX& a, long d, const zz_pEXModulus& F) { zz_pEX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pEX.h") NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lzz_pX.h0000644417616742025610000010761214064716022017703 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_pX__H #define NTL_zz_pX__H #include #include #include #include #include #include NTL_OPEN_NNS // some cross-over points #define NTL_zz_pX_MOD_CROSSOVER (zz_pX_mod_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_MUL_CROSSOVER (zz_pX_mul_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_NEWTON_CROSSOVER (zz_pX_newton_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_DIV_CROSSOVER (zz_pX_div_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_HalfGCD_CROSSOVER (zz_pX_halfgcd_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_GCD_CROSSOVER (zz_pX_gcd_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_BERMASS_CROSSOVER (zz_pX_bermass_crossover[zz_pInfo->PrimeCnt]) #define NTL_zz_pX_TRACE_CROSSOVER (zz_pX_trace_crossover[zz_pInfo->PrimeCnt]) extern const long zz_pX_mod_crossover[]; extern const long zz_pX_mul_crossover[]; extern const long zz_pX_newton_crossover[]; extern const long zz_pX_div_crossover[]; extern const long zz_pX_halfgcd_crossover[]; extern const long zz_pX_gcd_crossover[]; extern const long zz_pX_bermass_crossover[]; extern const long zz_pX_trace_crossover[]; /************************************************************ zz_pX The class zz_pX implements polynomial arithmetic modulo p. Polynomials are represented as vec_zz_p's. If f is a zz_pX, then f.rep is a vec_zz_p. The zero polynomial is represented as a zero length vector. Otherwise. f.rep[0] is the constant-term, and f.rep[f.rep.length()-1] is the leading coefficient, which is always non-zero. The member f.rep is public, so the vector representation is fully accessible. Use the member function normalize() to strip leading zeros. **************************************************************/ class zz_pE; // forward declaration class zz_pXModulus; class fftRep; class zz_pXMultiplier; class zz_pX { public: typedef zz_p coeff_type; typedef zz_pE residue_type; typedef zz_pXModulus modulus_type; typedef zz_pXMultiplier multiplier_type; typedef fftRep fft_type; vec_zz_p rep; typedef vec_zz_p VectorBaseType; /*************************************************************** Constructors, Destructors, and Assignment ****************************************************************/ zz_pX() {} // initial value 0 explicit zz_pX(long a) { *this = a; } explicit zz_pX(zz_p a) { *this = a; } zz_pX(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); } inline zz_pX(long i, zz_p c); inline zz_pX(long i, long c); inline zz_pX(INIT_MONO_TYPE, long i, zz_p c); inline zz_pX(INIT_MONO_TYPE, long i, long c); inline zz_pX(INIT_MONO_TYPE, long i); inline zz_pX& operator=(long a); inline zz_pX& operator=(zz_p a); // default copy constructor and assignment // default destructor void normalize(); // strip leading zeros void SetMaxLength(long n) // pre-allocate space for n coefficients. // Value is unchanged { rep.SetMaxLength(n); } void kill() // free space held by this polynomial. Value becomes 0. { rep.kill(); } void SetLength(long n) { rep.SetLength(n); } zz_p& operator[](long i) { return rep[i]; } const zz_p& operator[](long i) const { return rep[i]; } void swap(zz_pX& x) { rep.swap(x.rep); } static const zz_pX& zero(); zz_pX(zz_pX& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { } }; NTL_DECLARE_RELOCATABLE((zz_pX*)) /******************************************************************** input and output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are then reduced modulo p, and leading zeros stripped. *********************************************************************/ NTL_SNS istream& operator>>(NTL_SNS istream& s, zz_pX& x); NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const zz_pX& a); /********************************************************** Some utility routines ***********************************************************/ inline long deg(const zz_pX& a) { return a.rep.length() - 1; } // degree of a polynomial. // note that the zero polynomial has degree -1. const zz_p coeff(const zz_pX& a, long i); // zero if i not in range void GetCoeff(zz_p& x, const zz_pX& a, long i); // x = a[i], or zero if i not in range const zz_p LeadCoeff(const zz_pX& a); // zero if a == 0 const zz_p ConstTerm(const zz_pX& a); // zero if a == 0 void SetCoeff(zz_pX& x, long i, zz_p a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pX& x, long i, long a); // x[i] = a, error is raised if i < 0 void SetCoeff(zz_pX& x, long i); // x[i] = 1, error is raised if i < 0 inline zz_pX::zz_pX(long i, zz_p a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(long i, long a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i, zz_p a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i, long a) { SetCoeff(*this, i, a); } inline zz_pX::zz_pX(INIT_MONO_TYPE, long i) { SetCoeff(*this, i); } void SetX(zz_pX& x); // x is set to the monomial X long IsX(const zz_pX& a); // test if x = X inline void clear(zz_pX& x) // x = 0 { x.rep.SetLength(0); } inline void set(zz_pX& x) // x = 1 { x.rep.SetLength(1); set(x.rep[0]); } inline void swap(zz_pX& x, zz_pX& y) // swap x & y (only pointers are swapped) { x.swap(y); } void random(zz_pX& x, long n); inline zz_pX random_zz_pX(long n) { zz_pX x; random(x, n); NTL_OPT_RETURN(zz_pX, x); } // generate a random polynomial of degree < n void trunc(zz_pX& x, const zz_pX& a, long m); // x = a % X^m inline zz_pX trunc(const zz_pX& a, long m) { zz_pX x; trunc(x, a, m); NTL_OPT_RETURN(zz_pX, x); } void RightShift(zz_pX& x, const zz_pX& a, long n); // x = a/X^n inline zz_pX RightShift(const zz_pX& a, long n) { zz_pX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } void LeftShift(zz_pX& x, const zz_pX& a, long n); // x = a*X^n inline zz_pX LeftShift(const zz_pX& a, long n) { zz_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } #ifndef NTL_TRANSITION inline zz_pX operator>>(const zz_pX& a, long n) { zz_pX x; RightShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator<<(const zz_pX& a, long n) { zz_pX x; LeftShift(x, a, n); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator<<=(zz_pX& x, long n) { LeftShift(x, x, n); return x; } inline zz_pX& operator>>=(zz_pX& x, long n) { RightShift(x, x, n); return x; } #endif void diff(zz_pX& x, const zz_pX& a); // x = derivative of a inline zz_pX diff(const zz_pX& a) { zz_pX x; diff(x, a); NTL_OPT_RETURN(zz_pX, x); } void MakeMonic(zz_pX& x); // makes x monic void reverse(zz_pX& c, const zz_pX& a, long hi); inline zz_pX reverse(const zz_pX& a, long hi) { zz_pX x; reverse(x, a, hi); NTL_OPT_RETURN(zz_pX, x); } inline void reverse(zz_pX& c, const zz_pX& a) { reverse(c, a, deg(a)); } inline zz_pX reverse(const zz_pX& a) { zz_pX x; reverse(x, a); NTL_OPT_RETURN(zz_pX, x); } inline void VectorCopy(vec_zz_p& x, const zz_pX& a, long n) { VectorCopy(x, a.rep, n); } inline vec_zz_p VectorCopy(const zz_pX& a, long n) { return VectorCopy(a.rep, n); } /******************************************************************* conversion routines ********************************************************************/ void conv(zz_pX& x, long a); inline zz_pX to_zz_pX(long a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, const ZZ& a); inline zz_pX to_zz_pX(const ZZ& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, zz_p a); inline zz_pX to_zz_pX(zz_p a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } void conv(zz_pX& x, const vec_zz_p& a); inline zz_pX to_zz_pX(const vec_zz_p& a) { zz_pX x; conv(x, a); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& zz_pX::operator=(zz_p a) { conv(*this, a); return *this; } inline zz_pX& zz_pX::operator=(long a) { conv(*this, a); return *this; } /* additional legacy conversions for v6 conversion regime */ inline void conv(zz_pX& x, const zz_pX& a) { x = a; } inline void conv(vec_zz_p& x, const zz_pX& a) { x = a.rep; } /* ------------------------------------- */ /************************************************************* Comparison **************************************************************/ long IsZero(const zz_pX& a); long IsOne(const zz_pX& a); inline long operator==(const zz_pX& a, const zz_pX& b) { return a.rep == b.rep; } inline long operator!=(const zz_pX& a, const zz_pX& b) { return !(a == b); } long operator==(const zz_pX& a, long b); long operator==(const zz_pX& a, zz_p b); inline long operator==(long a, const zz_pX& b) { return b == a; } inline long operator==(zz_p a, const zz_pX& b) { return b == a; } inline long operator!=(const zz_pX& a, long b) { return !(a == b); } inline long operator!=(const zz_pX& a, zz_p b) { return !(a == b); } inline long operator!=(long a, const zz_pX& b) { return !(a == b); } inline long operator!=(zz_p a, const zz_pX& b) { return !(a == b); } /*************************************************************** Addition ****************************************************************/ void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b void negate(zz_pX& x, const zz_pX& a); // x = -a // scalar versions void add(zz_pX & x, const zz_pX& a, zz_p b); // x = a + b inline void add(zz_pX& x, const zz_pX& a, long b) { add(x, a, to_zz_p(b)); } inline void add(zz_pX& x, zz_p a, const zz_pX& b) { add(x, b, a); } inline void add(zz_pX& x, long a, const zz_pX& b) { add(x, b, a); } void sub(zz_pX & x, const zz_pX& a, zz_p b); // x = a - b inline void sub(zz_pX& x, const zz_pX& a, long b) { sub(x, a, to_zz_p(b)); } void sub(zz_pX& x, zz_p a, const zz_pX& b); inline void sub(zz_pX& x, long a, const zz_pX& b) { sub(x, to_zz_p(a), b); } inline zz_pX operator+(const zz_pX& a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(const zz_pX& a, zz_p b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(const zz_pX& a, long b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(zz_p a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator+(long a, const zz_pX& b) { zz_pX x; add(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, zz_p b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(const zz_pX& a, long b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(zz_p a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator-(long a, const zz_pX& b) { zz_pX x; sub(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator+=(zz_pX& x, const zz_pX& b) { add(x, x, b); return x; } inline zz_pX& operator+=(zz_pX& x, zz_p b) { add(x, x, b); return x; } inline zz_pX& operator+=(zz_pX& x, long b) { add(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, const zz_pX& b) { sub(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, zz_p b) { sub(x, x, b); return x; } inline zz_pX& operator-=(zz_pX& x, long b) { sub(x, x, b); return x; } inline zz_pX operator-(const zz_pX& a) { zz_pX x; negate(x, a); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator++(zz_pX& x) { add(x, x, 1); return x; } inline void operator++(zz_pX& x, int) { add(x, x, 1); } inline zz_pX& operator--(zz_pX& x) { sub(x, x, 1); return x; } inline void operator--(zz_pX& x, int) { sub(x, x, 1); } /***************************************************************** Multiplication ******************************************************************/ void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b void sqr(zz_pX& x, const zz_pX& a); inline zz_pX sqr(const zz_pX& a) { zz_pX x; sqr(x, a); NTL_OPT_RETURN(zz_pX, x); } // x = a^2 void mul(zz_pX& x, const zz_pX& a, zz_p b); inline void mul(zz_pX& x, const zz_pX& a, long b) { mul(x, a, to_zz_p(b)); } inline void mul(zz_pX& x, zz_p a, const zz_pX& b) { mul(x, b, a); } inline void mul(zz_pX& x, long a, const zz_pX& b) { mul(x, b, a); } inline zz_pX operator*(const zz_pX& a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(const zz_pX& a, zz_p b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(const zz_pX& a, long b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(zz_p a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator*(long a, const zz_pX& b) { zz_pX x; mul(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator*=(zz_pX& x, const zz_pX& b) { mul(x, x, b); return x; } inline zz_pX& operator*=(zz_pX& x, zz_p b) { mul(x, x, b); return x; } inline zz_pX& operator*=(zz_pX& x, long b) { mul(x, x, b); return x; } void PlainMul(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses the "classical" algorithm void PlainSqr(zz_pX& x, const zz_pX& a); // always uses the "classical" algorithm void FFTMul(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses the FFT void FFTSqr(zz_pX& x, const zz_pX& a); // always uses the FFT void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); // x = a * b % X^n inline zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n) { zz_pX x; MulTrunc(x, a, b, n); NTL_OPT_RETURN(zz_pX, x); } void PlainMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); void SqrTrunc(zz_pX& x, const zz_pX& a, long n); // x = a^2 % X^n inline zz_pX SqrTrunc(const zz_pX& a, long n) { zz_pX x; SqrTrunc(x, a, n); NTL_OPT_RETURN(zz_pX, x); } void PlainSqrTrunc(zz_pX& x, const zz_pX& a, long n); void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n); void power(zz_pX& x, const zz_pX& a, long e); inline zz_pX power(const zz_pX& a, long e) { zz_pX x; power(x, a, e); NTL_OPT_RETURN(zz_pX, x); } // The following data structures and routines allow one // to hand-craft various algorithms, using the FFT convolution // algorithms directly. // Look in the file zz_pX.c for examples. // FFT representation of polynomials class fftRep { public: long k; // a 2^k point representation long MaxK; // maximum space allocated long len; // length of truncated FFT long NumPrimes; UniqueArray tbl[4]; fftRep() : k(-1), MaxK(-1), len(0), NumPrimes(0) { } fftRep(const fftRep& R) : k(-1), MaxK(-1), len(0), NumPrimes(0) { *this = R; } fftRep(INIT_SIZE_TYPE, long InitK) : k(-1), MaxK(-1), len(0), NumPrimes(0) { SetSize(InitK); } fftRep& operator=(const fftRep&); void SetSize(long NewK); void DoSetSize(long NewK, long NewNumPrimes); }; void TofftRep_trunc(fftRep& y, const zz_pX& x, long k, long len, long lo, long hi); inline void TofftRep_trunc(fftRep& y, const zz_pX& x, long k, long len) { TofftRep_trunc(y, x, k, len, 0, deg(x)); } inline void TofftRep(fftRep& y, const zz_pX& x, long k, long lo, long hi) // computes an n = 2^k point convolution of x[lo..hi]. { TofftRep_trunc(y, x, k, 1L << k, lo, hi); } inline void TofftRep(fftRep& y, const zz_pX& x, long k) { TofftRep(y, x, k, 0, deg(x)); } void RevTofftRep(fftRep& y, const vec_zz_p& x, long k, long lo, long hi, long offset); // computes an n = 2^k point convolution of X^offset*x[lo..hi] mod X^n-1 // using "inverted" evaluation points. void FromfftRep(zz_pX& x, fftRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // only the coefficients lo..hi are computed // NOTE: this version destroys the data in y // non-destructive versions of the above void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi, fftRep& temp); void NDFromfftRep(zz_pX& x, const fftRep& y, long lo, long hi); void RevFromfftRep(vec_zz_p& x, fftRep& y, long lo, long hi); // converts from FFT-representation to coefficient representation // using "inverted" evaluation points. // only the coefficients lo..hi are computed void FromfftRep(zz_p* x, fftRep& y, long lo, long hi); // convert out coefficients lo..hi of y, store result in x. // no normalization is done. // direct manipulation of FFT reps void mul(fftRep& z, const fftRep& x, const fftRep& y); void sub(fftRep& z, const fftRep& x, const fftRep& y); void add(fftRep& z, const fftRep& x, const fftRep& y); void reduce(fftRep& x, const fftRep& a, long k); // reduces a 2^l point FFT-rep to a 2^k point FFT-rep void AddExpand(fftRep& x, const fftRep& a); // x = x + (an "expanded" version of a) /************************************************************* Division **************************************************************/ void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); // q = a/b, r = a%b void div(zz_pX& q, const zz_pX& a, const zz_pX& b); // q = a/b void div(zz_pX& q, const zz_pX& a, zz_p b); inline void div(zz_pX& q, const zz_pX& a, long b) { div(q, a, to_zz_p(b)); } void rem(zz_pX& r, const zz_pX& a, const zz_pX& b); // r = a%b long divide(zz_pX& q, const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 void InvTrunc(zz_pX& x, const zz_pX& a, long m); // computes x = a^{-1} % X^m // constant term must be non-zero inline zz_pX InvTrunc(const zz_pX& a, long m) { zz_pX x; InvTrunc(x, a, m); NTL_OPT_RETURN(zz_pX, x); } // These always use "classical" arithmetic void PlainDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); void PlainDiv(zz_pX& q, const zz_pX& a, const zz_pX& b); void PlainRem(zz_pX& r, const zz_pX& a, const zz_pX& b); // These always use FFT arithmetic void FFTDivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); void FFTDiv(zz_pX& q, const zz_pX& a, const zz_pX& b); void FFTRem(zz_pX& r, const zz_pX& a, const zz_pX& b); void PlainInvTrunc(zz_pX& x, const zz_pX& a, long m); // always uses "classical" algorithm // ALIAS RESTRICTION: input may not alias output void NewtonInvTrunc(zz_pX& x, const zz_pX& a, long m); // uses a Newton Iteration with the FFT. // ALIAS RESTRICTION: input may not alias output inline zz_pX operator/(const zz_pX& a, const zz_pX& b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator/(const zz_pX& a, zz_p b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX operator/(const zz_pX& a, long b) { zz_pX x; div(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator/=(zz_pX& x, zz_p b) { div(x, x, b); return x; } inline zz_pX& operator/=(zz_pX& x, long b) { div(x, x, b); return x; } inline zz_pX& operator/=(zz_pX& x, const zz_pX& b) { div(x, x, b); return x; } inline zz_pX operator%(const zz_pX& a, const zz_pX& b) { zz_pX x; rem(x, a, b); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator%=(zz_pX& x, const zz_pX& b) { rem(x, x, b); return x; } /*********************************************************** GCD's ************************************************************/ void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). inline zz_pX GCD(const zz_pX& a, const zz_pX& b) { zz_pX x; GCD(x, a, b); NTL_OPT_RETURN(zz_pX, x); } void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // d = gcd(a,b), a s + b t = d void PlainXGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // same as above, but uses classical algorithm void PlainGCD(zz_pX& x, const zz_pX& a, const zz_pX& b); // always uses "cdlassical" arithmetic class zz_pXMatrix { private: zz_pXMatrix(const zz_pXMatrix&); // disable zz_pX elts[2][2]; public: zz_pXMatrix() { } void operator=(const zz_pXMatrix&); zz_pX& operator() (long i, long j) { return elts[i][j]; } const zz_pX& operator() (long i, long j) const { return elts[i][j]; } }; void HalfGCD(zz_pXMatrix& M_out, const zz_pX& U, const zz_pX& V, long d_red); // deg(U) > deg(V), 1 <= d_red <= deg(U)+1. // // This computes a 2 x 2 polynomial matrix M_out such that // M_out * (U, V)^T = (U', V')^T, // where U', V' are consecutive polynomials in the Euclidean remainder // sequence of U, V, and V' is the polynomial of highest degree // satisfying deg(V') <= deg(U) - d_red. void XHalfGCD(zz_pXMatrix& M_out, zz_pX& U, zz_pX& V, long d_red); // same as above, except that U is replaced by U', and V by V' /************************************************************* Modular Arithmetic without pre-conditioning **************************************************************/ // arithmetic mod f. // all inputs and outputs are polynomials of degree less than deg(f). // ASSUMPTION: f is assumed monic, and deg(f) > 0. // NOTE: if you want to do many computations with a fixed f, // use the zz_pXModulus data structure and associated routines below. void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f); // x = (a * b) % f inline zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f) { zz_pX x; MulMod(x, a, b, f); NTL_OPT_RETURN(zz_pX, x); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = a^2 % f inline zz_pX SqrMod(const zz_pX& a, const zz_pX& f) { zz_pX x; SqrMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = (a * X) mod f inline zz_pX MulByXMod(const zz_pX& a, const zz_pX& f) { zz_pX x; MulByXMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f); // x = a^{-1} % f, error is a is not invertible inline zz_pX InvMod(const zz_pX& a, const zz_pX& f) { zz_pX x; InvMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f // otherwise, returns 1 and sets x = (a, f) /****************************************************************** Modular Arithmetic with Pre-conditioning *******************************************************************/ // If you need to do a lot of arithmetic modulo a fixed f, // build zz_pXModulus F for f. This pre-computes information about f // that speeds up the computation a great deal. class zz_pXModulus { public: zz_pXModulus() : UseFFT(0), n(-1) { } zz_pX f; // the modulus long UseFFT;// flag indicating whether FFT should be used. long n; // n = deg(f) long k; // least k s/t 2^k >= n long l; // least l s/t 2^l >= 2n-3 fftRep FRep; // 2^k point rep of f // H = rev((rev(f))^{-1} rem X^{n-1}) fftRep HRep; // 2^l point rep of H OptionalVal< Lazy > tracevec; // extra level of indirection to ensure relocatability zz_pXModulus(const zz_pX& ff); operator const zz_pX& () const { return f; } const zz_pX& val() const { return f; } }; NTL_DECLARE_RELOCATABLE((zz_pXModulus*)) inline long deg(const zz_pXModulus& F) { return F.n; } void build(zz_pXModulus& F, const zz_pX& f); // deg(f) > 0 void rem21(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f // deg(a) <= 2(n-1), where n = F.n = deg(f) void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f, no restrictions on deg(a); makes repeated calls to rem21 inline zz_pX operator%(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; rem(x, a, F); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F) { rem(x, x, F); return x; } void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F); void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F); inline zz_pX operator/(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; div(x, a, F); NTL_OPT_RETURN(zz_pX, x); } inline zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F) { div(x, x, F); return x; } void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); // x = (a * b) % f // deg(a), deg(b) < n inline zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F) { zz_pX x; MulMod(x, a, b, F); NTL_OPT_RETURN(zz_pX, x); } void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a^2 % f // deg(a) < n inline zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F) { zz_pX x; SqrMod(x, a, F); NTL_OPT_RETURN(zz_pX, x); } void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F); // x = a^e % f, e >= 0 inline zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F) { PowerMod(x, a, ZZ_expo(e), F); } inline zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F) { zz_pX x; PowerMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F); // x = X^e % f, e >= 0 inline zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F) { PowerXMod(x, ZZ_expo(e), F); } inline zz_pX PowerXMod(long e, const zz_pXModulus& F) { zz_pX x; PowerXMod(x, e, F); NTL_OPT_RETURN(zz_pX, x); } void PowerXPlusAMod(zz_pX& x, zz_p a, const ZZ& e, const zz_pXModulus& F); // x = (X + a)^e % f, e >= 0 inline zz_pX PowerXPlusAMod(zz_p a, const ZZ& e, const zz_pXModulus& F) { zz_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } inline void PowerXPlusAMod(zz_pX& x, zz_p a, long e, const zz_pXModulus& F) { PowerXPlusAMod(x, a, ZZ_expo(e), F); } inline zz_pX PowerXPlusAMod(zz_p a, long e, const zz_pXModulus& F) { zz_pX x; PowerXPlusAMod(x, a, e, F); NTL_OPT_RETURN(zz_pX, x); } // If you need to compute a * b % f for a fixed b, but for many a's // (for example, computing powers of b modulo f), it is // much more efficient to first build a zz_pXMultiplier B for b, // and then use the routine below. class zz_pXMultiplier { public: zz_pXMultiplier() : UseFFT(0) { } zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F); zz_pX b; long UseFFT; fftRep B1; fftRep B2; const zz_pX& val() const { return b; } }; void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F); void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // x = (a * b) % f inline zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { zz_pX x; MulMod(x, a, B, F); NTL_OPT_RETURN(zz_pX, x); } /******************************************************* Evaluation and related problems ********************************************************/ void BuildFromRoots(zz_pX& x, const vec_zz_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() inline zz_pX BuildFromRoots(const vec_zz_p& a) { zz_pX x; BuildFromRoots(x, a); NTL_OPT_RETURN(zz_pX, x); } void eval(zz_p& b, const zz_pX& f, zz_p a); // b = f(a) inline zz_p eval(const zz_pX& f, zz_p a) { zz_p x; eval(x, f, a); return x; } void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a); // b[i] = f(a[i]) inline vec_zz_p eval(const zz_pX& f, const vec_zz_p& a) { vec_zz_p x; eval(x, f, a); NTL_OPT_RETURN(vec_zz_p, x); } void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b); // computes f such that f(a[i]) = b[i] inline zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b) { zz_pX x; interpolate(x, a, b); NTL_OPT_RETURN(zz_pX, x); } /***************************************************************** vectors of zz_pX's *****************************************************************/ typedef Vec vec_zz_pX; /********************************************************** Modular Composition and Minimal Polynomials ***********************************************************/ // algorithms for computing g(h) mod f void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); // x = g(h) mod f inline zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F) { zz_pX x; CompMod(x, g, h, F); NTL_OPT_RETURN(zz_pX, x); } void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1,2) void Comp3Mod(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1..3) // The routine build (see below) which is implicitly called // by the various compose and UpdateMap routines builds a table // of polynomials. // If zz_pXArgBound > 0, then the table is limited in // size to approximamtely that many KB. // If zz_pXArgBound <= 0, then it is ignored, and space is allocated // so as to maximize speed. // Initially, zz_pXArgBound = 0. // If a single h is going to be used with many g's // then you should build a zz_pXArgument for h, // and then use the compose routine below. // build computes and stores h, h^2, ..., h^m mod f. // After this pre-computation, composing a polynomial of degree // roughly n with h takes n/m multiplies mod f, plus n^2 // scalar multiplies. // Thus, increasing m increases the space requirement and the pre-computation // time, but reduces the composition time. // If zz_pXArgBound > 0, a table of size less than m may be built. struct zz_pXArgument { vec_zz_pX H; }; extern NTL_CHEAP_THREAD_LOCAL long zz_pXArgBound; void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); // m must be > 0, otherwise an error is raised void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); inline zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F) { zz_pX x; CompMod(x, g, H, F); NTL_OPT_RETURN(zz_pX, x); } // New alternative CompMod strategy that just reduces to // matrix multiplication ... struct zz_pXNewArgument { Mat mat; zz_pX poly; }; void build(zz_pXNewArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); void CompMod(zz_pX& x, const zz_pX& g, const zz_pXNewArgument& H, const zz_pXModulus& F); void reduce(zz_pXNewArgument& H, const zz_pXModulus& F); void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXNewArgument& H, const zz_pXModulus& F); #ifndef NTL_TRANSITION void UpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); inline vec_zz_p UpdateMap(const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F) { vec_zz_p x; UpdateMap(x, a, B, F); NTL_OPT_RETURN(vec_zz_p, x); } #endif /* computes (a, b), (a, (b*X)%f), ..., (a, (b*X^{n-1})%f), where ( , ) denotes the vector inner product. This is really a "transposed" MulMod by B. */ void PlainUpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pX& b, const zz_pX& f); // same as above, but uses only classical arithmetic void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); // computes (a, 1), (a, h), ..., (a, h^{k-1} % f) // this is really a "transposed" compose. inline vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F) { vec_zz_p x; ProjectPowers(x, a, k, h, F); NTL_OPT_RETURN(vec_zz_p, x); } void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); inline vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F) { vec_zz_p x; ProjectPowers(x, a, k, H, F); NTL_OPT_RETURN(vec_zz_p, x); } // same as above, but uses a pre-computed zz_pXArgument inline void project(zz_p& x, const vec_zz_p& a, const zz_pX& b) { InnerProduct(x, a, b.rep); } inline zz_p project(const vec_zz_p& a, const zz_pX& b) { zz_p x; project(x, a, b); return x; } void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; // m is a bound on the degree of the polynomial; // required: a.length() >= 2*m inline zz_pX MinPolySeq(const vec_zz_p& a, long m) { zz_pX x; MinPolySeq(x, a, m); NTL_OPT_RETURN(zz_pX, x); } void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; ProbMinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { ProbMinPolyMod(h, g, F, F.n); } inline zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; ProbMinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // computes the monic minimal polynomial if (g mod f). // m = a bound on the degree of the minimal polynomial. // If this argument is not supplied, it defaults to deg(f). // The algorithm is probabilistic, always returns a divisor of // the minimal polynomial, and returns a proper divisor with // probability at most m/p. void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; MinPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { MinPolyMod(h, g, F, F.n); } inline zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; MinPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // same as above, but guarantees that result is correct void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); inline zz_pX IrredPolyMod(const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX x; IrredPolyMod(x, g, F, m); NTL_OPT_RETURN(zz_pX, x); } inline void IrredPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F) { IrredPolyMod(h, g, F, F.n); } inline zz_pX IrredPolyMod(const zz_pX& g, const zz_pXModulus& F) { zz_pX x; IrredPolyMod(x, g, F); NTL_OPT_RETURN(zz_pX, x); } // same as above, but assumes that f is irreducible, // or at least that the minimal poly of g is itself irreducible. // The algorithm is deterministic (and is always correct). /***************************************************************** Traces, norms, resultants ******************************************************************/ void TraceVec(vec_zz_p& S, const zz_pX& f); inline vec_zz_p TraceVec(const zz_pX& f) { vec_zz_p x; TraceVec(x, f); NTL_OPT_RETURN(vec_zz_p, x); } void FastTraceVec(vec_zz_p& S, const zz_pX& f); void PlainTraceVec(vec_zz_p& S, const zz_pX& f); void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F); inline zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F) { zz_p x; TraceMod(x, a, F); return x; } void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f); inline zz_p TraceMod(const zz_pX& a, const zz_pX& f) { zz_p x; TraceMod(x, a, f); return x; } void ComputeTraceVec(const zz_pXModulus& F); void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f); inline zz_p NormMod(const zz_pX& a, const zz_pX& f) { zz_p x; NormMod(x, a, f); return x; } void resultant(zz_p& rres, const zz_pX& a, const zz_pX& b); inline zz_p resultant(const zz_pX& a, const zz_pX& b) { zz_p x; resultant(x, a, b); return x; } void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f); // g = char poly of (a mod f) // only implemented for p >= deg(f)+1 inline zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f) { zz_pX x; CharPolyMod(x, a, f); NTL_OPT_RETURN(zz_pX, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/lzz_pXFactoring.h0000644417616742025610000001546214064716022021541 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_zz_pXFactoring__H #define NTL_zz_pXFactoring__H #include #include #include NTL_OPEN_NNS /************************************************************ factorization routines ************************************************************/ void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f); inline vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f) { vec_pair_zz_pX_long x; SquareFreeDecomp(x, f); return x; } // Performs square-free decomposition. // f must be monic. // If f = prod_i g_i^i, then u is set to a lest of pairs (g_i, i). // The list is is increasing order of i, with trivial terms // (i.e., g_i = 1) deleted. void FindRoots(vec_zz_p& x, const zz_pX& f); inline vec_zz_p FindRoots(const zz_pX& f) { vec_zz_p x; FindRoots(x, f); return x; } // f is monic, and has deg(f) distinct roots. // returns the list of roots void FindRoot(zz_p& root, const zz_pX& f); inline zz_p FindRoot(const zz_pX& f) { zz_p x; FindRoot(x, f); return x; } // finds a single root of ff. // assumes that f is monic and splits into distinct linear factors void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX SFBerlekamp(const zz_pX& f, long verbose=0) { vec_zz_pX x; SFBerlekamp(x, f, verbose); return x; } // Assumes f is square-free and monic. // returns list of factors of f. // Uses "Berlekamp" appraoch. void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); inline vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0) { vec_pair_zz_pX_long x; berlekamp(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Berlekamp" appraoch. extern NTL_CHEAP_THREAD_LOCAL long zz_pX_BlockingFactor; // Controls GCD blocking for DDF. void DDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); inline vec_pair_zz_pX_long DDF(const zz_pX& f, const zz_pX& h, long verbose=0) { vec_pair_zz_pX_long x; DDF(x, f, h, verbose); return x; } // Performs distinct-degree factorization. // Assumes f is monic and square-free, and h = X^p mod f // Obsolete: see NewDDF, below. extern NTL_CHEAP_THREAD_LOCAL long zz_pX_GCDTableSize; /* = 4 */ // Controls GCD blocking for NewDDF void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); inline vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h, long verbose=0) { vec_pair_zz_pX_long x; NewDDF(x, f, h, verbose); return x; } // same as above, but uses baby-step/giant-step method void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& b, long d, long verbose=0); inline vec_zz_pX EDF(const zz_pX& f, const zz_pX& b, long d, long verbose=0) { vec_zz_pX x; EDF(x, f, b, d, verbose); return x; } // Performs equal-degree factorization. // f is monic, square-free, and all irreducible factors have same degree. // b = X^p mod f. // d = degree of irreducible factors of f // Space for the trace-map computation can be controlled via ComposeBound. void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX RootEDF(const zz_pX& f, long verbose=0) { vec_zz_pX x; RootEDF(x, f, verbose); return x; } // EDF for d==1 void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0); inline vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0) { vec_zz_pX x; SFCanZass(x, f, verbose); return x; } // Assumes f is square-free. // returns list of factors of f. // Uses "Cantor/Zassenhaus" approach. void SFCanZass1(vec_pair_zz_pX_long& u, zz_pX& h, const zz_pX& f, long verbose=0); // Not intended for general use. void SFCanZass2(vec_zz_pX& factors, const vec_pair_zz_pX_long& u, const zz_pX& h, long verbose=0); // Not intended for general use. void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); inline vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0) { vec_pair_zz_pX_long x; CanZass(x, f, verbose); return x; } // returns a list of factors, with multiplicities. // f must be monic. // Uses "Cantor/Zassenhaus" approach. void mul(zz_pX& f, const vec_pair_zz_pX_long& v); inline zz_pX mul(const vec_pair_zz_pX_long& v) { zz_pX x; mul(x, v); return x; } // multiplies polynomials, with multiplicities /************************************************************* irreducible poly's: tests and constructions **************************************************************/ long ProbIrredTest(const zz_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test // the test can err only if f is reducible, and the // error probability is bounded by p^{-iter}. long DetIrredTest(const zz_pX& f); // performs a recursive deterministic irreducibility test // fast in the worst-case (when input is irreducible). long IterIrredTest(const zz_pX& f); // performs an iterative deterministic irreducibility test, // based on DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pX& f, long n); inline zz_pX BuildIrred_zz_pX(long n) { zz_pX x; BuildIrred(x, n); NTL_OPT_RETURN(zz_pX, x); } // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pX& f, const zz_pX& g); inline zz_pX BuildRandomIrred(const zz_pX& g) { zz_pX x; BuildRandomIrred(x, g); NTL_OPT_RETURN(zz_pX, x); } // g is a monic irreducible polynomial. // constructs a random monic irreducible polynomial f of the same degree. long ComputeDegree(const zz_pX& h, const zz_pXModulus& F); // f = F.f is assumed to be an "equal degree" polynomial // h = X^p mod f // the common degree of the irreducible factors of f is computed // This routine is useful in counting points on elliptic curves long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm // the return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b); inline zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& b) { zz_pX x; TraceMap(x, a, d, F, b); return x; } // w = a+a^q+...+^{q^{d-1}} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pX.h") void PowerCompose(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F); inline zz_pX PowerCompose(const zz_pX& a, long d, const zz_pXModulus& F) { zz_pX x; PowerCompose(x, a, d, F); return x; } // w = X^{q^d} mod f; // it is assumed that d >= 0, and b = X^q mod f, q a power of p // Space allocation can be controlled via ComposeBound (see "zz_pX.h") NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_GF2.h0000644417616742025610000001056514064716022017634 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_GF2__H #define NTL_mat_GF2__H #include #include NTL_OPEN_NNS typedef Mat mat_GF2; // some backward compaitibilty stuff inline void conv(mat_GF2& x, const vec_vec_GF2& a) { MakeMatrix(x, a); } inline mat_GF2 to_mat_GF2(const vec_vec_GF2& a) { mat_GF2 x; conv(x, a); NTL_OPT_RETURN(mat_GF2, x); } void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); inline void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B) { add(X, A, B); } inline void negate(mat_GF2& X, const mat_GF2& A) { X = A; } void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b); void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B); void mul(mat_GF2& X, const mat_GF2& A, GF2 b); inline void mul(mat_GF2& X, GF2 a, const mat_GF2& B) { mul(X, B, a); } inline void mul(mat_GF2& X, const mat_GF2& A, long b) { mul(X, A, to_GF2(b)); } inline void mul(mat_GF2& X, long a, const mat_GF2& B) { mul(X, B, a); } void ident(mat_GF2& X, long n); inline mat_GF2 ident_mat_GF2(long n) { mat_GF2 X; ident(X, n); NTL_OPT_RETURN(mat_GF2, X); } void random(mat_GF2& x, long n, long m); inline mat_GF2 random_mat_GF2(long n, long m) { mat_GF2 x; random(x, n, m); NTL_OPT_RETURN(mat_GF2, x); } long IsIdent(const mat_GF2& A, long n); void transpose(mat_GF2& X, const mat_GF2& A); void solve(ref_GF2 d, vec_GF2& X, const mat_GF2& A, const vec_GF2& b); void solve(ref_GF2 d, const mat_GF2& A, vec_GF2& x, const vec_GF2& b); void inv(ref_GF2 d, mat_GF2& X, const mat_GF2& A); inline void sqr(mat_GF2& X, const mat_GF2& A) { mul(X, A, A); } inline mat_GF2 sqr(const mat_GF2& A) { mat_GF2 X; sqr(X, A); NTL_OPT_RETURN(mat_GF2, X); } void inv(mat_GF2& X, const mat_GF2& A); inline mat_GF2 inv(const mat_GF2& A) { mat_GF2 X; inv(X, A); NTL_OPT_RETURN(mat_GF2, X); } void power(mat_GF2& X, const mat_GF2& A, const ZZ& e); inline mat_GF2 power(const mat_GF2& A, const ZZ& e) { mat_GF2 X; power(X, A, e); NTL_OPT_RETURN(mat_GF2, X); } inline void power(mat_GF2& X, const mat_GF2& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_GF2 power(const mat_GF2& A, long e) { mat_GF2 X; power(X, A, e); NTL_OPT_RETURN(mat_GF2, X); } void diag(mat_GF2& X, long n, GF2 d); inline mat_GF2 diag(long n, GF2 d) { mat_GF2 X; diag(X, n, d); NTL_OPT_RETURN(mat_GF2, X); } long IsDiag(const mat_GF2& A, long n, GF2 d); long gauss(mat_GF2& M); long gauss(mat_GF2& M, long w); void image(mat_GF2& X, const mat_GF2& A); void kernel(mat_GF2& X, const mat_GF2& A); void determinant(ref_GF2 x, const mat_GF2& a); inline GF2 determinant(const mat_GF2& a) { GF2 x; determinant(x, a); return x; } inline mat_GF2 transpose(const mat_GF2 & a) { mat_GF2 x; transpose(x, a); NTL_OPT_RETURN(mat_GF2, x); } void clear(mat_GF2& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b); inline mat_GF2 operator-(const mat_GF2& a) { return a; } // matrix/scalar multiplication: inline mat_GF2 operator*(const mat_GF2& a, GF2 b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(const mat_GF2& a, long b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(GF2 a, const mat_GF2& b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } inline mat_GF2 operator*(long a, const mat_GF2& b) { mat_GF2 x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2, x); } // matrix/vector multiplication: vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b); vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b); // assignment operator notation: inline mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a) { add(x, x, a); return x; } inline mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a) { sub(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a) { mul(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, GF2 a) { mul(x, x, a); return x; } inline mat_GF2& operator*=(mat_GF2& x, long a) { mul(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_GF2E.h0000644417616742025610000001146114064716022017735 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_GF2E__H #define NTL_mat_GF2E__H #include #include NTL_OPEN_NNS typedef Mat mat_GF2E; void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); inline void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B) { add(X, A, B); } inline void negate(mat_GF2E& X, const mat_GF2E& A) { X = A; } void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B); void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b); inline void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B) { mul(X, B, a); } void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b); inline void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B) { mul(X, B, a); } inline void mul(mat_GF2E& X, const mat_GF2E& A, long b) { mul(X, A, to_GF2(b)); } inline void mul(mat_GF2E& X, long a, const mat_GF2E& B) { mul(X, B, a); } void ident(mat_GF2E& X, long n); inline mat_GF2E ident_mat_GF2E(long n) { mat_GF2E X; ident(X, n); NTL_OPT_RETURN(mat_GF2E, X); } void random(mat_GF2E& x, long n, long m); inline mat_GF2E random_mat_GF2E(long n, long m) { mat_GF2E x; random(x, n, m); NTL_OPT_RETURN(mat_GF2E, x); } void determinant(GF2E& d, const mat_GF2E& A); long IsIdent(const mat_GF2E& A, long n); void transpose(mat_GF2E& X, const mat_GF2E& A); void solve(GF2E& d, vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); void solve(GF2E& d, const mat_GF2E& A, vec_GF2E& x, const vec_GF2E& b); void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A); inline void sqr(mat_GF2E& X, const mat_GF2E& A) { mul(X, A, A); } inline mat_GF2E sqr(const mat_GF2E& A) { mat_GF2E X; sqr(X, A); NTL_OPT_RETURN(mat_GF2E, X); } void inv(mat_GF2E& X, const mat_GF2E& A); inline mat_GF2E inv(const mat_GF2E& A) { mat_GF2E X; inv(X, A); NTL_OPT_RETURN(mat_GF2E, X); } void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e); inline mat_GF2E power(const mat_GF2E& A, const ZZ& e) { mat_GF2E X; power(X, A, e); NTL_OPT_RETURN(mat_GF2E, X); } inline void power(mat_GF2E& X, const mat_GF2E& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_GF2E power(const mat_GF2E& A, long e) { mat_GF2E X; power(X, A, e); NTL_OPT_RETURN(mat_GF2E, X); } void diag(mat_GF2E& X, long n, const GF2E& d); inline mat_GF2E diag(long n, const GF2E& d) { mat_GF2E X; diag(X, n, d); NTL_OPT_RETURN(mat_GF2E, X); } long IsDiag(const mat_GF2E& A, long n, const GF2E& d); long gauss(mat_GF2E& M); long gauss(mat_GF2E& M, long w); void image(mat_GF2E& X, const mat_GF2E& A); void kernel(mat_GF2E& X, const mat_GF2E& A); // miscellaneous: inline GF2E determinant(const mat_GF2E& a) { GF2E x; determinant(x, a); return x; } // functional variant of determinant inline mat_GF2E transpose(const mat_GF2E& a) { mat_GF2E x; transpose(x, a); NTL_OPT_RETURN(mat_GF2E, x); } void clear(mat_GF2E& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2E& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a); // matrix/scalar multiplication: inline mat_GF2E operator*(const mat_GF2E& a, const GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const mat_GF2E& a, GF2 b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const mat_GF2E& a, long b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(const GF2E& a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(GF2 a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } inline mat_GF2E operator*(long a, const mat_GF2E& b) { mat_GF2E x; mul(x, a, b); NTL_OPT_RETURN(mat_GF2E, x); } // matrix/vector multiplication: vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b); vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b); // assignment operator notation: inline mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a) { add(x, x, a); return x; } inline mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a) { sub(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, GF2 a) { mul(x, x, a); return x; } inline mat_GF2E& operator*=(mat_GF2E& x, long a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_RR.h0000644417616742025610000000716714064716022017605 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_RR__H #define NTL_mat_RR__H #include #include NTL_OPEN_NNS typedef Mat mat_RR; void add(mat_RR& X, const mat_RR& A, const mat_RR& B); void sub(mat_RR& X, const mat_RR& A, const mat_RR& B); void negate(mat_RR& X, const mat_RR& A); void mul(mat_RR& X, const mat_RR& A, const mat_RR& B); void mul(vec_RR& x, const mat_RR& A, const vec_RR& b); void mul(vec_RR& x, const vec_RR& a, const mat_RR& B); void mul(mat_RR& X, const mat_RR& A, const RR& b); void mul(mat_RR& X, const mat_RR& A, double b); inline void mul(mat_RR& X, const RR& a, const mat_RR& B) { mul(X, B, a); } inline void mul(mat_RR& X, double a, const mat_RR& B) { mul(X, B, a); } void ident(mat_RR& X, long n); inline mat_RR ident_mat_RR(long n) { mat_RR X; ident(X, n); NTL_OPT_RETURN(mat_RR, X); } void determinant(RR& d, const mat_RR& A); long IsIdent(const mat_RR& A, long n); void transpose(mat_RR& X, const mat_RR& A); void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b); void inv(RR& d, mat_RR& X, const mat_RR& A); inline void sqr(mat_RR& X, const mat_RR& A) { mul(X, A, A); } inline mat_RR sqr(const mat_RR& A) { mat_RR X; sqr(X, A); NTL_OPT_RETURN(mat_RR, X); } void inv(mat_RR& X, const mat_RR& A); inline mat_RR inv(const mat_RR& A) { mat_RR X; inv(X, A); NTL_OPT_RETURN(mat_RR, X); } void power(mat_RR& X, const mat_RR& A, const ZZ& e); inline mat_RR power(const mat_RR& A, const ZZ& e) { mat_RR X; power(X, A, e); NTL_OPT_RETURN(mat_RR, X); } inline void power(mat_RR& X, const mat_RR& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_RR power(const mat_RR& A, long e) { mat_RR X; power(X, A, e); NTL_OPT_RETURN(mat_RR, X); } void diag(mat_RR& X, long n, const RR& d); inline mat_RR diag(long n, const RR& d) { mat_RR X; diag(X, n, d); NTL_OPT_RETURN(mat_RR, X); } long IsDiag(const mat_RR& A, long n, const RR& d); // miscellaneous: RR determinant(const mat_RR& a); // functional variant of determinant inline mat_RR transpose(const mat_RR & a) { mat_RR x; transpose(x, a); NTL_OPT_RETURN(mat_RR, x); } void clear(mat_RR& a); // x = 0 (dimension unchanged) long IsZero(const mat_RR& a); // test if a is the zero matrix (any dimension) // operator notation: mat_RR operator+(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a, const mat_RR& b); mat_RR operator*(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a); // matrix/vector multiplication: vec_RR operator*(const mat_RR& a, const vec_RR& b); vec_RR operator*(const vec_RR& a, const mat_RR& b); // matrix/scalar multiplication: inline mat_RR operator*(const mat_RR& a, const RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(const mat_RR& a, double b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(const RR& a, const mat_RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } inline mat_RR operator*(double a, const mat_RR& b) { mat_RR x; mul(x, a, b); NTL_OPT_RETURN(mat_RR, x); } // assignment operator notation: inline mat_RR& operator+=(mat_RR& x, const mat_RR& a) { add(x, x, a); return x; } inline mat_RR& operator-=(mat_RR& x, const mat_RR& a) { sub(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, const mat_RR& a) { mul(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, const RR& a) { mul(x, x, a); return x; } inline mat_RR& operator*=(mat_RR& x, double a) { mul(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, const mat_RR& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_ZZ.h0000644417616742025610000001060014064716022017607 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_ZZ__H #define NTL_mat_ZZ__H #include #include #include #include NTL_OPEN_NNS typedef Mat mat_ZZ; void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void negate(mat_ZZ& X, const mat_ZZ& A); void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B); void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b); inline void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B) { mul(X, B, a); } void mul(mat_ZZ& X, const mat_ZZ& A, long b); inline void mul(mat_ZZ& X, long a, const mat_ZZ& B) { mul(X, B, a); } void ident(mat_ZZ& X, long n); inline mat_ZZ ident_mat_ZZ(long n) { mat_ZZ X; ident(X, n); NTL_OPT_RETURN(mat_ZZ, X); } long IsIdent(const mat_ZZ& A, long n); void diag(mat_ZZ& X, long n, const ZZ& d); inline mat_ZZ diag(long n, const ZZ& d) { mat_ZZ X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ, X); } long IsDiag(const mat_ZZ& A, long n, const ZZ& d); void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0); void solve(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b, long deterministic=0); void solve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b); inline void HenselSolve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b) { solve1(d_out, x_out, A, b); } // for backward compatability only void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0); inline void sqr(mat_ZZ& X, const mat_ZZ& A) { mul(X, A, A); } inline mat_ZZ sqr(const mat_ZZ& A) { mat_ZZ X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ, X); } void inv(mat_ZZ& X, const mat_ZZ& A); inline mat_ZZ inv(const mat_ZZ& A) { mat_ZZ X; inv(X, A); NTL_OPT_RETURN(mat_ZZ, X); } void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e); inline mat_ZZ power(const mat_ZZ& A, const ZZ& e) { mat_ZZ X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ, X); } inline void power(mat_ZZ& X, const mat_ZZ& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ power(const mat_ZZ& A, long e) { mat_ZZ X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ, X); } void transpose(mat_ZZ& X, const mat_ZZ& A); inline mat_ZZ transpose(const mat_ZZ& A) { mat_ZZ x; transpose(x, A); NTL_OPT_RETURN(mat_ZZ, x); } void conv(mat_zz_p& x, const mat_ZZ& a); inline mat_zz_p to_mat_zz_p(const mat_ZZ& a) { mat_zz_p x; conv(x, a); NTL_OPT_RETURN(mat_zz_p, x); } void conv(mat_ZZ_p& x, const mat_ZZ& a); inline mat_ZZ_p to_mat_ZZ_p(const mat_ZZ& a) { mat_ZZ_p x; conv(x, a); NTL_OPT_RETURN(mat_ZZ_p, x); } long CRT(mat_ZZ& g, ZZ& a, const mat_zz_p& G); // miscellaneous: inline ZZ determinant(const mat_ZZ& a, long deterministic=0) { ZZ x; determinant(x, a, deterministic); return x; } // functional variant of determinant void clear(mat_ZZ& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a); // matrix/scalar multiplication: inline mat_ZZ operator*(const mat_ZZ& a, const ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(const mat_ZZ& a, long b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(const ZZ& a, const mat_ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } inline mat_ZZ operator*(long a, const mat_ZZ& b) { mat_ZZ x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ, x); } // matrix/vector multiplication: vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b); vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b); // assignment operator notation: inline mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a) { add(x, x, a); return x; } inline mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a) { sub(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a) { mul(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline mat_ZZ& operator*=(mat_ZZ& x, long a) { mul(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_ZZ_p.h0000644417616742025610000001303514064716022020133 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_ZZ_p__H #define NTL_mat_ZZ_p__H #include #include #include #include NTL_OPEN_NNS typedef Mat mat_ZZ_p; // ****************** opaque stuff ************** struct mat_ZZ_p_opaque_body { virtual ~mat_ZZ_p_opaque_body() { } virtual mat_ZZ_p_opaque_body* clone() const = 0; virtual long NumRows() const = 0; virtual long NumCols() const = 0; virtual void mul(mat_ZZ_p& X, const mat_ZZ_p& A) const = 0; virtual void mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A) const = 0; }; mat_ZZ_p_opaque_body *mat_ZZ_p_opaque_body_move(mat_ZZ_p& A); struct mat_ZZ_p_opaque { CopiedPtr ptr; void move(mat_ZZ_p& A) { this->ptr.reset(mat_ZZ_p_opaque_body_move(A)); } long NumRows() const { return ptr ? ptr->NumRows() : 0; } long NumCols() const { return ptr ? ptr->NumCols() : 0; } bool initialized() const { return ptr != 0; } }; inline void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p_opaque& B) { if (!B.ptr) LogicError("mul: uninitialzed mat_ZZ_p_opaque"); else B.ptr->mul(X, A); } inline void mul_transpose(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p_opaque& B) { if (!B.ptr) LogicError("mul: uninitialzed mat_ZZ_p_opaque"); else B.ptr->mul_transpose(X, A); } void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void negate(mat_ZZ_p& X, const mat_ZZ_p& A); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b); void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b); inline void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B) { mul(X, B, a); } inline void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B) { mul(X, B, a); } void ident(mat_ZZ_p& X, long n); inline mat_ZZ_p ident_mat_ZZ_p(long n) { mat_ZZ_p X; ident(X, n); NTL_OPT_RETURN(mat_ZZ_p, X); } void random(mat_ZZ_p& x, long n, long m); inline mat_ZZ_p random_mat_ZZ_p(long n, long m) { mat_ZZ_p x; random(x, n, m); NTL_OPT_RETURN(mat_ZZ_p, x); } void determinant(ZZ_p& d, const mat_ZZ_p& A); long IsIdent(const mat_ZZ_p& A, long n); void transpose(mat_ZZ_p& X, const mat_ZZ_p& A); void solve(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b); void solve(ZZ_p& d, const mat_ZZ_p& A, vec_ZZ_p& x, const vec_ZZ_p& b); void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A); inline void sqr(mat_ZZ_p& X, const mat_ZZ_p& A) { mul(X, A, A); } inline mat_ZZ_p sqr(const mat_ZZ_p& A) { mat_ZZ_p X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ_p, X); } void inv(mat_ZZ_p& X, const mat_ZZ_p& A); inline mat_ZZ_p inv(const mat_ZZ_p& A) { mat_ZZ_p X; inv(X, A); NTL_OPT_RETURN(mat_ZZ_p, X); } void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e); inline mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e) { mat_ZZ_p X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_p, X); } inline void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ_p power(const mat_ZZ_p& A, long e) { mat_ZZ_p X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_p, X); } void diag(mat_ZZ_p& X, long n, const ZZ_p& d); inline mat_ZZ_p diag(long n, const ZZ_p& d) { mat_ZZ_p X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ_p, X); } long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d); long gauss(mat_ZZ_p& M); long gauss(mat_ZZ_p& M, long w); void image(mat_ZZ_p& X, const mat_ZZ_p& A); void kernel(mat_ZZ_p& X, const mat_ZZ_p& A); inline ZZ_p determinant(const mat_ZZ_p& a) { ZZ_p x; determinant(x, a); return x; } // functional variant of determinant inline mat_ZZ_p transpose(const mat_ZZ_p & a) { mat_ZZ_p x; transpose(x, a); NTL_OPT_RETURN(mat_ZZ_p, x); } void clear(mat_ZZ_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a); // matrix/scalar multiplication: inline mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(const mat_ZZ_p& a, long b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } inline mat_ZZ_p operator*(long a, const mat_ZZ_p& b) { mat_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_p, x); } // matrix/vector multiplication: vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b); // assignment operator notation: inline mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a) { add(x, x, a); return x; } inline mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a) { sub(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_p& operator*=(mat_ZZ_p& x, long a) { mul(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_ZZ_pE.h0000644417616742025610000001156314064716022020244 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_ZZ_pE__H #define NTL_mat_ZZ_pE__H #include NTL_OPEN_NNS typedef Mat mat_ZZ_pE; void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b); inline void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B) { mul(X, B, a); } inline void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B) { mul(X, B, a); } inline void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B) { mul(X, B, a); } void ident(mat_ZZ_pE& X, long n); inline mat_ZZ_pE ident_mat_ZZ_pE(long n) { mat_ZZ_pE X; ident(X, n); NTL_OPT_RETURN(mat_ZZ_pE, X); } void random(mat_ZZ_pE& x, long n, long m); inline mat_ZZ_pE random_mat_ZZ_pE(long n, long m) { mat_ZZ_pE x; random(x, n, m); NTL_OPT_RETURN(mat_ZZ_pE, x); } void determinant(ZZ_pE& d, const mat_ZZ_pE& A); inline ZZ_pE determinant(const mat_ZZ_pE& A) { ZZ_pE d; determinant(d, A); NTL_OPT_RETURN(ZZ_pE, d); } long IsIdent(const mat_ZZ_pE& A, long n); void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A); inline mat_ZZ_pE transpose(const mat_ZZ_pE& A) { mat_ZZ_pE X; transpose(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void solve(ZZ_pE& d, vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); void solve(ZZ_pE& d, const mat_ZZ_pE& A, vec_ZZ_pE& x, const vec_ZZ_pE& b); void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A); inline void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A) { mul(X, A, A); } inline mat_ZZ_pE sqr(const mat_ZZ_pE& A) { mat_ZZ_pE X; sqr(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A); inline mat_ZZ_pE inv(const mat_ZZ_pE& A) { mat_ZZ_pE X; inv(X, A); NTL_OPT_RETURN(mat_ZZ_pE, X); } void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e); inline mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e) { mat_ZZ_pE X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_pE, X); } inline void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_ZZ_pE power(const mat_ZZ_pE& A, long e) { mat_ZZ_pE X; power(X, A, e); NTL_OPT_RETURN(mat_ZZ_pE, X); } void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d); inline mat_ZZ_pE diag(long n, const ZZ_pE& d) { mat_ZZ_pE X; diag(X, n, d); NTL_OPT_RETURN(mat_ZZ_pE, X); } long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d); long gauss(mat_ZZ_pE& M); long gauss(mat_ZZ_pE& M, long w); void image(mat_ZZ_pE& X, const mat_ZZ_pE& A); void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A); void clear(mat_ZZ_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a); // matrix/scalar multiplication: inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } inline mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b) { mat_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_ZZ_pE, x); } // matrix/vector multiplication: vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b); // assignment operator notation: inline mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { add(x, x, a); return x; } inline mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { sub(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a) { mul(x, x, a); return x; } inline mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_lzz_p.h0000644417616742025610000001337314064716022020414 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_zz_p__H #define NTL_mat_zz_p__H #include #include NTL_OPEN_NNS typedef Mat mat_zz_p; void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void negate(mat_zz_p& X, const mat_zz_p& A); void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b); void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B); void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b); void mul(mat_zz_p& X, const mat_zz_p& A, long b); inline void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B) { mul(X, B, a); } inline void mul(mat_zz_p& X, long a, const mat_zz_p& B) { mul(X, B, a); } void ident(mat_zz_p& X, long n); inline mat_zz_p ident_mat_zz_p(long n) { mat_zz_p X; ident(X, n); NTL_OPT_RETURN(mat_zz_p, X); } void random(mat_zz_p& x, long n, long m); inline mat_zz_p random_mat_zz_p(long n, long m) { mat_zz_p x; random(x, n, m); NTL_OPT_RETURN(mat_zz_p, x); } long IsIdent(const mat_zz_p& A, long n); void transpose(mat_zz_p& X, const mat_zz_p& A); // ************************ void relaxed_solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b, bool relax=true); void relaxed_solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b, bool relax=true); void relaxed_inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax=true); inline void relaxed_inv(mat_zz_p& X, const mat_zz_p& A, bool relax=true) { zz_p d; relaxed_inv(d, X, A, relax); if (d == 0) ArithmeticError("inv: non-invertible matrix"); } inline mat_zz_p relaxed_inv(const mat_zz_p& A, bool relax=true) { mat_zz_p X; relaxed_inv(X, A, relax); NTL_OPT_RETURN(mat_zz_p, X); } void relaxed_determinant(zz_p& d, const mat_zz_p& A, bool relax=true); inline zz_p relaxed_determinant(const mat_zz_p& a, bool relax=true) { zz_p x; relaxed_determinant(x, a, relax); return x; } void relaxed_power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e, bool relax=true); inline mat_zz_p relaxed_power(const mat_zz_p& A, const ZZ& e, bool relax=true) { mat_zz_p X; relaxed_power(X, A, e, relax); NTL_OPT_RETURN(mat_zz_p, X); } inline void relaxed_power(mat_zz_p& X, const mat_zz_p& A, long e, bool relax=true) { relaxed_power(X, A, ZZ_expo(e), relax); } inline mat_zz_p relaxed_power(const mat_zz_p& A, long e, bool relax=true) { mat_zz_p X; relaxed_power(X, A, e, relax); NTL_OPT_RETURN(mat_zz_p, X); } // *********************** inline void solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { relaxed_solve(d, x, A, b, false); } inline void solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b) { relaxed_solve(d, A, x, b, false); } inline void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A) { relaxed_inv(d, X, A, false); } inline void inv(mat_zz_p& X, const mat_zz_p& A) { relaxed_inv(X, A, false); } inline mat_zz_p inv(const mat_zz_p& A) { return relaxed_inv(A, false); } inline void determinant(zz_p& d, const mat_zz_p& A) { relaxed_determinant(d, A, false); } inline zz_p determinant(const mat_zz_p& a) { return relaxed_determinant(a, false); } inline void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e) { relaxed_power(X, A, e, false); } inline mat_zz_p power(const mat_zz_p& A, const ZZ& e) { return relaxed_power(A, e, false); } inline void power(mat_zz_p& X, const mat_zz_p& A, long e) { relaxed_power(X, A, e, false); } inline mat_zz_p power(const mat_zz_p& A, long e) { return relaxed_power(A, e, false); } // ************************ inline void sqr(mat_zz_p& X, const mat_zz_p& A) { mul(X, A, A); } inline mat_zz_p sqr(const mat_zz_p& A) { mat_zz_p X; sqr(X, A); NTL_OPT_RETURN(mat_zz_p, X); } void diag(mat_zz_p& X, long n, zz_p d); inline mat_zz_p diag(long n, zz_p d) { mat_zz_p X; diag(X, n, d); NTL_OPT_RETURN(mat_zz_p, X); } long IsDiag(const mat_zz_p& A, long n, zz_p d); long gauss(mat_zz_p& M); long gauss(mat_zz_p& M, long w); void image(mat_zz_p& X, const mat_zz_p& A); void kernel(mat_zz_p& X, const mat_zz_p& A); // miscellaneous: inline mat_zz_p transpose(const mat_zz_p& a) { mat_zz_p x; transpose(x, a); NTL_OPT_RETURN(mat_zz_p, x); } void clear(mat_zz_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a); // matrix/scalar multiplication: inline mat_zz_p operator*(const mat_zz_p& a, zz_p b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(const mat_zz_p& a, long b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(zz_p a, const mat_zz_p& b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } inline mat_zz_p operator*(long a, const mat_zz_p& b) { mat_zz_p x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_p, x); } // matrix/vector multiplication: vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b); vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b); // assignment operator notation: inline mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a) { add(x, x, a); return x; } inline mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a) { sub(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a) { mul(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, zz_p a) { mul(x, x, a); return x; } inline mat_zz_p& operator*=(mat_zz_p& x, long a) { mul(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_lzz_pE.h0000644417616742025610000001156414064716022020521 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_zz_pE__H #define NTL_mat_zz_pE__H #include NTL_OPEN_NNS typedef Mat mat_zz_pE; void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void negate(mat_zz_pE& X, const mat_zz_pE& A); void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, long b); inline void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B) { mul(X, B, a); } inline void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B) { mul(X, B, a); } inline void mul(mat_zz_pE& X, long a, const mat_zz_pE& B) { mul(X, B, a); } void ident(mat_zz_pE& X, long n); inline mat_zz_pE ident_mat_zz_pE(long n) { mat_zz_pE X; ident(X, n); NTL_OPT_RETURN(mat_zz_pE, X); } void random(mat_zz_pE& x, long n, long m); inline mat_zz_pE random_mat_zz_pE(long n, long m) { mat_zz_pE x; random(x, n, m); NTL_OPT_RETURN(mat_zz_pE, x); } void determinant(zz_pE& d, const mat_zz_pE& A); inline zz_pE determinant(const mat_zz_pE& A) { zz_pE d; determinant(d, A); NTL_OPT_RETURN(zz_pE, d); } long IsIdent(const mat_zz_pE& A, long n); void transpose(mat_zz_pE& X, const mat_zz_pE& A); inline mat_zz_pE transpose(const mat_zz_pE& A) { mat_zz_pE X; transpose(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void solve(zz_pE& d, vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); void solve(zz_pE& d, const mat_zz_pE& A, vec_zz_pE& x, const vec_zz_pE& b); void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A); inline void sqr(mat_zz_pE& X, const mat_zz_pE& A) { mul(X, A, A); } inline mat_zz_pE sqr(const mat_zz_pE& A) { mat_zz_pE X; sqr(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void inv(mat_zz_pE& X, const mat_zz_pE& A); inline mat_zz_pE inv(const mat_zz_pE& A) { mat_zz_pE X; inv(X, A); NTL_OPT_RETURN(mat_zz_pE, X); } void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e); inline mat_zz_pE power(const mat_zz_pE& A, const ZZ& e) { mat_zz_pE X; power(X, A, e); NTL_OPT_RETURN(mat_zz_pE, X); } inline void power(mat_zz_pE& X, const mat_zz_pE& A, long e) { power(X, A, ZZ_expo(e)); } inline mat_zz_pE power(const mat_zz_pE& A, long e) { mat_zz_pE X; power(X, A, e); NTL_OPT_RETURN(mat_zz_pE, X); } void diag(mat_zz_pE& X, long n, const zz_pE& d); inline mat_zz_pE diag(long n, const zz_pE& d) { mat_zz_pE X; diag(X, n, d); NTL_OPT_RETURN(mat_zz_pE, X); } long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d); long gauss(mat_zz_pE& M); long gauss(mat_zz_pE& M, long w); void image(mat_zz_pE& X, const mat_zz_pE& A); void kernel(mat_zz_pE& X, const mat_zz_pE& A); void clear(mat_zz_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a); // matrix/scalar multiplication: inline mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const mat_zz_pE& a, long b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } inline mat_zz_pE operator*(long a, const mat_zz_pE& b) { mat_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(mat_zz_pE, x); } // matrix/vector multiplication: vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b); // assignment operator notation: inline mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a) { add(x, x, a); return x; } inline mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a) { sub(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a) { mul(x, x, a); return x; } inline mat_zz_pE& operator*=(mat_zz_pE& x, long a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_poly_ZZ.h0000644417616742025610000000031114064716022020650 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_poly_ZZ__H #define NTL_mat_poly_ZZ__H #include #include NTL_OPEN_NNS void CharPoly(ZZX& f, const mat_ZZ& M, long deterministic=0); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_poly_ZZ_p.h0000644417616742025610000000030014064716022021165 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_poly_ZZ_p__H #define NTL_mat_poly_ZZ_p__H #include #include NTL_OPEN_NNS void CharPoly(ZZ_pX& f, const mat_ZZ_p& M); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/mat_poly_lzz_p.h0000644417616742025610000000030214064716022021443 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_mat_poly_zz_p__H #define NTL_mat_poly_zz_p__H #include #include NTL_OPEN_NNS void CharPoly(zz_pX& f, const mat_zz_p& M); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/matrix.h0000644417616742025610000001401414064716022017712 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_matrix__H #define NTL_matrix__H #include #include // matrix templates NTL_OPEN_NNS template class Mat { private: struct Fixer { long m; explicit Fixer(long _m) : m(_m) { } void operator()(Vec& v) { v.FixLength(m); } }; public: // pseudo-private fields Vec< Vec > _mat__rep; long _mat__numcols; // really public fields typedef typename Vec::value_type value_type; typedef typename Vec::reference reference; typedef typename Vec::const_reference const_reference; Mat() : _mat__numcols(0) { } Mat(const Mat& a); Mat& operator=(const Mat& a); Mat(INIT_SIZE_TYPE, long n, long m); void kill(); void SetDims(long n, long m); long NumRows() const { return _mat__rep.length(); } long NumCols() const { return _mat__numcols; } Vec& operator[](long i) { return _mat__rep[i]; } const Vec& operator[](long i) const { return _mat__rep[i]; } Vec& operator()(long i) { return _mat__rep[i-1]; } const Vec& operator()(long i) const { return _mat__rep[i-1]; } reference operator()(long i, long j) { return _mat__rep[i-1][j-1]; } const_reference operator()(long i, long j) const { return _mat__rep[i-1][j-1]; } const_reference get(long i, long j) const { return _mat__rep[i].get(j); } void put(long i, long j, const T& a) { _mat__rep[i].put(j, a); } template void put(long i, long j, const U& a) { _mat__rep[i].put(j, a); } long position(const Vec& a) const { return _mat__rep.position(a); } long position1(const Vec& a) const { return _mat__rep.position1(a); } long alias(const Vec& a) const { return a.fixed() && a.length() == NumCols() && position1(a) != -1; } Mat(Mat& x, INIT_TRANS_TYPE) : _mat__rep(x._mat__rep, INIT_TRANS), _mat__numcols(x._mat__numcols) { } void swap(Mat& other) { _mat__rep.swap(other._mat__rep); _ntl_swap(_mat__numcols, other._mat__numcols); } void move(Mat& other) { Mat tmp; tmp.swap(other); tmp.swap(*this); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) Mat(Mat&& other) noexcept : Mat() { this->move(other); } #ifndef NTL_DISABLE_MOVE_ASSIGN Mat& operator=(Mat&& other) noexcept { this->move(other); return *this; } #endif #endif }; template NTL_DECLARE_RELOCATABLE((Mat*)) template inline const Vec< Vec >& rep(const Mat& a) { return a._mat__rep; } template Mat::Mat(const Mat& src) : _mat__rep(src._mat__rep), _mat__numcols(src._mat__numcols) { long i, nrows; nrows = _mat__rep.length(); for (i = 0; i < nrows; i++) _mat__rep[i].FixAtCurrentLength(); } template Mat& Mat::operator=(const Mat& src) { if (this == &src) return *this; if (src.NumCols() == 0) SetDims(src.NumRows(), src.NumCols()); else if (NumCols() != src.NumCols()) { Mat tmp(src); this->swap(tmp); } else { long i, init, len; init = _mat__rep.MaxLength(); len = src._mat__rep.length(); _mat__rep = src._mat__rep; for (i = init; i < len; i++) _mat__rep[i].FixAtCurrentLength(); } return *this; } template Mat::Mat(INIT_SIZE_TYPE, long n, long m) : _mat__numcols(0) { SetDims(n, m); } template void Mat::kill() { Mat tmp; this->swap(tmp); } // This is designed to provide strong ES template void Mat::SetDims(long n, long m) { if (n < 0 || m < 0) LogicError("SetDims: bad args"); long init = _mat__rep.MaxLength(); if (init > 0 && m != _mat__numcols) { Mat tmp; tmp._mat__rep.SetLengthAndApply(n, Fixer(m)); tmp._mat__numcols = m; this->swap(tmp); } else { _mat__rep.SetLengthAndApply(n, Fixer(m)); _mat__numcols = m; } } template void MakeMatrix(Mat& x, const Vec< Vec >& a) { long n = a.length(); if (n == 0) { x.SetDims(0, 0); return; } long m = a[0].length(); long i; for (i = 1; i < n; i++) if (a[i].length() != m) LogicError("nonrectangular matrix"); x.SetDims(n, m); for (i = 0; i < n; i++) x[i] = a[i]; } template bool MakeMatrixStatus(Mat& x, const Vec< Vec >& a) { long n = a.length(); if (n == 0) { x.SetDims(0, 0); return false; } long m = a[0].length(); long i; for (i = 1; i < n; i++) if (a[i].length() != m) return true; x.SetDims(n, m); for (i = 0; i < n; i++) x[i] = a[i]; return false; } template void swap(Mat& X, Mat& Y) { X.swap(Y); } template long operator==(const Mat& a, const Mat& b) { if (a.NumCols() != b.NumCols()) return 0; if (a.NumRows() != b.NumRows()) return 0; long n = a.NumRows(); long i; for (i = 0; i < n; i++) if (a[i] != b[i]) return 0; return 1; } template long operator!=(const Mat& a, const Mat& b) { return !(a == b); } template NTL_SNS istream& operator>>(NTL_SNS istream& s, Mat& x) { Vec< Vec > buf; NTL_INPUT_CHECK_RET(s, s >> buf); if (MakeMatrixStatus(x, buf)) NTL_INPUT_ERROR(s, "non-rectangular matrix detected on input"); return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Mat& a) { long n = a.NumRows(); long i; s << "["; for (i = 0; i < n; i++) { s << a[i]; s << "\n"; } s << "]"; return s; } // conversion template void conv(Mat& x, const Mat& a) { x.SetDims(a.NumRows(), a.NumCols()); conv(x._mat__rep, a._mat__rep); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair.h0000644417616742025610000000327714064716022017352 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair__H #define NTL_pair__H #include // pair templates NTL_OPEN_NNS template class Pair { public: S a; T b; Pair() { } Pair(const S& x, const T& y) : a(x), b(y) { } }; template NTL_DECLARE_RELOCATABLE_WHEN((Pair*)) { return DeclareRelocatableType((S*)0) && DeclareRelocatableType((T*)0); } // FIXME: remove CV-qualifiers and S and T? template inline Pair cons(const S& x, const T& y) { return Pair(x, y); } template inline long operator==(const Pair& x, const Pair& y) { return x.a == y.a && x.b == y.b; } template inline long operator!=(const Pair& x, const Pair& y) { return !(x == y); } template NTL_SNS istream& operator>>(NTL_SNS istream& s, Pair& x) { long c; S a; T b; if (!s) NTL_INPUT_ERROR(s, "bad pair input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') NTL_INPUT_ERROR(s, "bad pair input"); s.get(); if (!(s >> a)) NTL_INPUT_ERROR(s, "bad pair input"); if (!(s >> b)) NTL_INPUT_ERROR(s, "bad pair input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != ']') NTL_INPUT_ERROR(s, "bad pair input"); s.get(); x.a = a; x.b = b; return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Pair& x) { return s << "[" << x.a << " " << x.b << "]"; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vector.h0000644417616742025610000005512114064716022017714 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vector__H #define NTL_vector__H #include #include struct _ntl_VectorHeader { long length; long alloc; long init; long fixed; }; union _ntl_AlignedVectorHeader { _ntl_VectorHeader h; double x1; long x2; char *x3; long double x4; }; #define NTL_VECTOR_HEADER_SIZE (sizeof(_ntl_AlignedVectorHeader)) #define NTL_VEC_HEAD(p) (& (((_ntl_AlignedVectorHeader *) (p.rep))[-1].h)) #ifndef NTL_RANGE_CHECK #define NTL_RANGE_CHECK_CODE(i) #else #define NTL_RANGE_CHECK_CODE(i) if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) LogicError("index out of range in Vec"); #endif // vectors are allocated in chunks of this size #ifndef NTL_VectorMinAlloc #define NTL_VectorMinAlloc (4) #endif // controls initialization during input #ifndef NTL_VectorInputBlock #define NTL_VectorInputBlock 50 #endif NTL_OPEN_NNS template void default_BlockDestroy(T* p, long n) { for (long i = 0; i < n; i++) p[i].~T(); // NOTE: this routine is only invoked through a Vec destructor // or a scope guard destructor, both of which are noexcept destructors. // therefore, if ~T() should throw, the program will terminate } template void BlockDestroy(T* p, long n) { default_BlockDestroy(p, n); } template void default_BlockConstruct(T* p, long n) { long i; NTL_SCOPE(guard) { default_BlockDestroy(p, i); }; for (i = 0; i < n; i++) (void) new(&p[i]) T; guard.relax(); // NOTE: we invoke T rather than T(), which would ensure // POD types get zeroed out, but only in compilers that // comply with C++03, which does not include MS compilers. // So we just use T, which is less expensive, and it is better // not to assume POD types get initialized. } template void BlockConstruct(T* p, long n) { default_BlockConstruct(p, n); } template void default_BlockConstructFromVec(T* p, long n, const T* q) { long i; NTL_SCOPE(guard) { default_BlockDestroy(p, i); }; for (i = 0; i < n; i++) (void) new(&p[i]) T(q[i]); guard.relax(); } template void BlockConstructFromVec(T* p, long n, const T* q) { default_BlockConstructFromVec(p, n, q); } template void default_BlockConstructFromObj(T* p, long n, const T& q) { long i; NTL_SCOPE(guard) { default_BlockDestroy(p, i); }; for (i = 0; i < n; i++) (void) new(&p[i]) T(q); guard.relax(); } template void BlockConstructFromObj(T* p, long n, const T& q) { default_BlockConstructFromObj(p, n, q); } template struct VecStrategy; template<> struct VecStrategy { // realloc-based relocation // we use the specialized memory management routines, if any template static void do_BlockDestroy(T* p, long n) { BlockDestroy(p, n); } template static void do_BlockConstruct(T* p, long n) { BlockConstruct(p, n); } template static void do_BlockConstructFromVec(T* p, long n, const T* q) { BlockConstructFromVec(p, n, q); } template static void do_BlockConstructFromObj(T* p, long n, const T& q) { BlockConstructFromObj(p, n, q); } }; template<> struct VecStrategy { // non-realloc-based relocation // we do not use the specialized memory management routines, even if // they are defined template static void do_BlockDestroy(T* p, long n) { default_BlockDestroy(p, n); } template static void do_BlockConstruct(T* p, long n) { default_BlockConstruct(p, n); } template static void do_BlockConstructFromVec(T* p, long n, const T* q) { default_BlockConstructFromVec(p, n, q); } template static void do_BlockConstructFromObj(T* p, long n, const T& q) { default_BlockConstructFromObj(p, n, q); } }; template class Vec { private: static void BlockDestroy(T* p, long n) { VecStrategy::do_BlockDestroy(p, n); } static void BlockConstruct(T* p, long n) { VecStrategy::do_BlockConstruct(p, n); } static void BlockConstructFromVec(T* p, long n, const T* q) { VecStrategy::do_BlockConstructFromVec(p, n, q); } static void BlockConstructFromObj(T* p, long n, const T& q) { VecStrategy::do_BlockConstructFromObj(p, n, q); } public: #ifdef NTL_SAFE_VECTORS static constexpr bool relocatable = DeclareRelocatableType((T*)0); static constexpr bool copyable = Relocate_aux_has_any_copy((T*)0); #endif class _vec_deleter { public: static void apply(T* p) { // WrappedPtr only calls this when p is non-null NTL_SNS free(((char *) p) - sizeof(_ntl_AlignedVectorHeader)); } }; WrappedPtr _vec__rep; Vec() { } Vec(INIT_SIZE_TYPE, long n) { SetLength(n); } Vec(INIT_SIZE_TYPE, long n, const T& a) { SetLength(n, a); } // the following copy constructor does not rely on // the assignment operator Vec(const Vec& a) { long src_len = a.length(); const T *src = a.elts(); AllocateTo(src_len); Init(src_len, src); AdjustLength(src_len); } Vec& operator=(const Vec& a); #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) Vec(Vec&& a) NTL_FAKE_NOEXCEPT { if (a.fixed()) { long src_len = a.length(); const T *src = a.elts(); AllocateTo(src_len); Init(src_len, src); AdjustLength(src_len); } else { _vec__rep.move(a._vec__rep); } } #ifndef NTL_DISABLE_MOVE_ASSIGN Vec& operator=(Vec&& a) NTL_FAKE_NOEXCEPT { if(fixed() || a.fixed()) { *this = a; } else { Vec tmp; tmp._vec__rep.swap(a._vec__rep); tmp._vec__rep.swap(this->_vec__rep); } return *this; } #endif #endif ~Vec() { if (!_vec__rep) return; BlockDestroy(_vec__rep.rep, NTL_VEC_HEAD(_vec__rep)->init); } void kill(); void SetMaxLength(long n); void FixLength(long n); void FixAtCurrentLength(); void QuickSetLength(long n) { NTL_VEC_HEAD(_vec__rep)->length = n; } void SetLength(long n) { if (_vec__rep && !NTL_VEC_HEAD(_vec__rep)->fixed && n >= 0 && n <= NTL_VEC_HEAD(_vec__rep)->init) NTL_VEC_HEAD(_vec__rep)->length = n; else DoSetLength(n); } void SetLength(long n, const T& a) { if (_vec__rep && !NTL_VEC_HEAD(_vec__rep)->fixed && n >= 0 && n <= NTL_VEC_HEAD(_vec__rep)->init) NTL_VEC_HEAD(_vec__rep)->length = n; else DoSetLength(n, a); } template void SetLengthAndApply(long n, F f) { if (_vec__rep && !NTL_VEC_HEAD(_vec__rep)->fixed && n >= 0 && n <= NTL_VEC_HEAD(_vec__rep)->init) NTL_VEC_HEAD(_vec__rep)->length = n; else DoSetLengthAndApply(n, f); } long length() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->length; } long MaxLength() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->init; } long allocated() const { return (!_vec__rep) ? 0 : NTL_VEC_HEAD(_vec__rep)->alloc; } long fixed() const { return _vec__rep && NTL_VEC_HEAD(_vec__rep)->fixed; } T& operator[](long i) { NTL_RANGE_CHECK_CODE(i) return _vec__rep[i]; } const T& operator[](long i) const { NTL_RANGE_CHECK_CODE(i) return _vec__rep[i]; } T& RawGet(long i) { return _vec__rep[i]; } const T& RawGet(long i) const { return _vec__rep[i]; } T& operator()(long i) { return (*this)[i-1]; } const T& operator()(long i) const { return (*this)[i-1]; } const T* elts() const { return _vec__rep; } T* elts() { return _vec__rep; } Vec(Vec& x, INIT_TRANS_TYPE) { _vec__rep.swap(x._vec__rep); } long position(const T& a) const; long position1(const T& a) const; void swap(Vec& y); void move(Vec& y); void append(const T& a); void append(const Vec& w); // Some compatibility with vec_GF2 const T& get(long i) const { return (*this)[i]; } void put(long i, const T& a) { (*this)[i] = a; } // Some STL compatibility typedef T value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type *iterator; typedef const value_type *const_iterator; const T* data() const { return elts(); } T* data() { return elts(); } T* begin() { return elts(); } const T* begin() const { return elts(); } T* end() { if (elts()) return elts() + length(); else return 0; } const T* end() const { if (elts()) return elts() + length(); else return 0; } T& at(long i) { if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) LogicError("index out of range in Vec"); return _vec__rep[i]; } const T& at(long i) const { if ((i) < 0 || !_vec__rep || (i) >= NTL_VEC_HEAD(_vec__rep)->length) LogicError("index out of range in Vec"); return _vec__rep[i]; } class Watcher { public: Vec& watched; explicit Watcher(Vec& _watched) : watched(_watched) {} ~Watcher() { if (watched.MaxLength() > NTL_RELEASE_THRESH) watched.kill(); } }; private: void DoSetLength(long n); void DoSetLength(long n, const T& a); template void DoSetLengthAndApply(long n, F& f); void AdjustLength(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->length = n; } void AdjustAlloc(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->alloc = n; } void AdjustMaxLength(long n) { if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->init = n; } void ReAllocate(long n, VecStrategy); void AllocateTo(long n); // reserves space for n items void Init(long n); // make sure first n entries are initialized void Init(long n, const T* src); // same, but use src void Init(long n, const T& src); // same, but use src #ifdef NTL_SAFE_VECTORS void ReAllocate(long n, VecStrategy); void InitMove(long n, T* src, std::true_type); void InitMove(long n, T* src, std::false_type); void InitCopyMove(long n, T* src, std::true_type); void InitCopyMove(long n, T* src, std::false_type); #endif template void InitAndApply(long n, F& f); }; template NTL_DECLARE_RELOCATABLE((Vec*)) #if (!defined(NTL_CLEAN_PTR)) template long Vec::position(const T& a) const { if (!_vec__rep) return -1; long num_alloc = NTL_VEC_HEAD(_vec__rep)->alloc; long num_init = NTL_VEC_HEAD(_vec__rep)->init; if (&a < _vec__rep || &a >= _vec__rep + num_alloc) return -1; long res = (&a) - _vec__rep; if (res < 0 || res >= num_alloc || _vec__rep + res != &a) return -1; if (res >= num_init) LogicError("position: reference to uninitialized object"); return res; } template long Vec::position1(const T& a) const { if (!_vec__rep) return -1; long len = NTL_VEC_HEAD(_vec__rep)->length; if (&a < _vec__rep || &a >= _vec__rep + len) return -1; long res = (&a) - _vec__rep; if (res < 0 || res >= len || _vec__rep + res != &a) return -1; return res; } #else template long Vec::position(const T& a) const { if (!_vec__rep) return -1; long num_alloc = NTL_VEC_HEAD(_vec__rep)->alloc; long num_init = NTL_VEC_HEAD(_vec__rep)->init; long res; res = 0; while (res < num_alloc && _vec__rep + res != &a) res++; if (res >= num_alloc) return -1; if (res >= num_init) LogicError("position: reference to uninitialized object"); return res; } template long Vec::position1(const T& a) const { if (!_vec__rep) return -1; long len = NTL_VEC_HEAD(_vec__rep)->length; long res; res = 0; while (res < len && _vec__rep + res != &a) res++; if (res >= len) return -1; return res; } #endif template void Vec::ReAllocate(long m, VecStrategy) { //std::cerr << "ReAllocate\n"; char *p = ((char *) _vec__rep.rep) - sizeof(_ntl_AlignedVectorHeader); p = (char *) NTL_SNS_REALLOC(p, m, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { MemoryError(); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->alloc = m; } #ifdef NTL_SAFE_VECTORS template void Vec::InitMove(long n, T *src, std::true_type) { long num_init = MaxLength(); if (n <= num_init) return; for (long i = 0; i < n-num_init; i++) (void) new(_vec__rep + num_init + i) T(std::move(src[i])); AdjustMaxLength(n); } #if 0 template void Vec::InitMove(long n, T *src, std::false_type) { Init(n, src); } #else // This version throws a runtime error, rather than a compile-time // error, if no copy contructor is available. // This increases backward compatibility. template void Vec::InitCopyMove(long n, T *src, std::true_type) { Init(n, src); } template void Vec::InitCopyMove(long n, T *src, std::false_type) { LogicError("cannot re-allocate vector: no copy constructor for type"); } template void Vec::InitMove(long n, T *src, std::false_type) { typedef std::integral_constant copy_it; InitCopyMove(n, src, copy_it()); } #endif template void Vec::ReAllocate(long m, VecStrategy) { Vec tmp; long src_len = length(); long src_init = MaxLength(); T *src = elts(); char *p = (char *) NTL_SNS_MALLOC(m, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { MemoryError(); } tmp._vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(tmp._vec__rep)->length = 0; NTL_VEC_HEAD(tmp._vec__rep)->alloc = m; NTL_VEC_HEAD(tmp._vec__rep)->init = 0; NTL_VEC_HEAD(tmp._vec__rep)->fixed = 0; typedef std::is_nothrow_move_constructible move_it; tmp.InitMove(src_init, src, move_it()); tmp.AdjustLength(src_len); tmp.swap(*this); } #endif template void Vec::AllocateTo(long n) { long m; if (n < 0) { LogicError("negative length in vector::SetLength"); } if (NTL_OVERFLOW(n, sizeof(T), 0)) ResourceError("excessive length in vector::SetLength"); if (_vec__rep && NTL_VEC_HEAD(_vec__rep)->fixed) { if (NTL_VEC_HEAD(_vec__rep)->length == n) return; else LogicError("SetLength: can't change this vector's length"); } if (n == 0) { return; } if (!_vec__rep) { m = ((n+NTL_VectorMinAlloc-1)/NTL_VectorMinAlloc) * NTL_VectorMinAlloc; char *p = (char *) NTL_SNS_MALLOC(m, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { MemoryError(); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->length = 0; NTL_VEC_HEAD(_vec__rep)->alloc = m; NTL_VEC_HEAD(_vec__rep)->init = 0; NTL_VEC_HEAD(_vec__rep)->fixed = 0; } else if (n > NTL_VEC_HEAD(_vec__rep)->alloc) { m = max(n, _ntl_vec_grow(NTL_VEC_HEAD(_vec__rep)->alloc)); m = ((m+NTL_VectorMinAlloc-1)/NTL_VectorMinAlloc) * NTL_VectorMinAlloc; ReAllocate(m, VecStrategy()); } } template void Vec::Init(long n) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstruct(_vec__rep + num_init, n-num_init); AdjustMaxLength(n); } template void Vec::Init(long n, const T *src) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstructFromVec(_vec__rep + num_init, n-num_init, src); AdjustMaxLength(n); } template void Vec::Init(long n, const T& src) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstructFromObj(_vec__rep + num_init, n-num_init, src); AdjustMaxLength(n); } template template void Vec::InitAndApply(long n, F& f) { long num_init = MaxLength(); if (n <= num_init) return; BlockConstruct(_vec__rep + num_init, n-num_init); NTL_SCOPE(guard) { BlockDestroy(_vec__rep + num_init, n - num_init); }; long i; for (i = num_init; i < n; i++) f(_vec__rep[i]); guard.relax(); AdjustMaxLength(n); } template void Vec::DoSetLength(long n) { AllocateTo(n); Init(n); AdjustLength(n); } template void Vec::DoSetLength(long n, const T& a) { // if vector gets moved, we have to worry about // a aliasing a vector element const T *src = &a; long pos = -1; if (n > allocated()) pos = position(a); AllocateTo(n); if (pos != -1) src = elts() + pos; Init(n, *src); AdjustLength(n); } template template void Vec::DoSetLengthAndApply(long n, F& f) { AllocateTo(n); InitAndApply(n, f); AdjustLength(n); } template void Vec::SetMaxLength(long n) { long OldLength = length(); SetLength(n); SetLength(OldLength); } template void Vec::FixLength(long n) { if (_vec__rep) LogicError("FixLength: can't fix this vector"); if (n < 0) LogicError("FixLength: negative length"); NTL_SCOPE(guard) { _vec__rep.kill(); }; if (n > 0) SetLength(n); else { char *p = (char *) NTL_SNS_MALLOC(0, sizeof(T), sizeof(_ntl_AlignedVectorHeader)); if (!p) { MemoryError(); } _vec__rep = (T *) (p + sizeof(_ntl_AlignedVectorHeader)); NTL_VEC_HEAD(_vec__rep)->length = 0; NTL_VEC_HEAD(_vec__rep)->init = 0; NTL_VEC_HEAD(_vec__rep)->alloc = 0; } NTL_VEC_HEAD(_vec__rep)->fixed = 1; guard.relax(); } template void Vec::FixAtCurrentLength() { if (fixed()) return; if (length() != MaxLength()) LogicError("FixAtCurrentLength: can't fix this vector"); if (_vec__rep) NTL_VEC_HEAD(_vec__rep)->fixed = 1; else FixLength(0); } template Vec& Vec::operator=(const Vec& a) { if (this == &a) return *this; long init = MaxLength(); long src_len = a.length(); const T *src = a.elts(); AllocateTo(src_len); T *dst = elts(); // NOTE: these assignments could throw if (src_len <= init) { long i; for (i = 0; i < src_len; i++) dst[i] = src[i]; } else { long i; for (i = 0; i < init; i++) dst[i] = src[i]; Init(src_len, src+init); } AdjustLength(src_len); return *this; } template void Vec::kill() { Vec tmp; this->swap(tmp); } template void Vec::swap(Vec& y) { long xf = fixed(); long yf = y.fixed(); if (xf != yf || (xf && NTL_VEC_HEAD(_vec__rep)->length != NTL_VEC_HEAD(y._vec__rep)->length)) LogicError("swap: can't swap these vectors"); _vec__rep.swap(y._vec__rep); } template void swap(Vec& x, Vec& y) { x.swap(y); } template void Vec::move(Vec& y) { // special logic to get exception handling right if (&y == this) return; if (fixed() || y.fixed()) LogicError("move: can't move these vectors"); Vec tmp; tmp._vec__rep.swap(y._vec__rep); tmp._vec__rep.swap(this->_vec__rep); } // EXCEPTIONS: provides strong ES template void Vec::append(const T& a) { long len = length(); long init = MaxLength(); long src_len = 1; // if vector gets moved, we have to worry about // a aliasing a vector element const T *src = &a; long pos = -1; if (len >= allocated()) pos = position(a); AllocateTo(len+src_len); // The logic here is copy-pasted from the append-vector // logic...mostly long i; T *dst = elts(); if (pos != -1) src = dst + pos; // NOTE: these assignments could throw if (len+src_len <= init) { for (i = 0; i < src_len; i++) dst[i+len] = src[i]; } else { for (i = 0; i < init-len; i++) dst[i+len] = src[i]; // make sure we use BlockConstructFromObj Init(src_len+len, *src); } AdjustLength(len+src_len); } template void append(Vec& v, const T& a) { v.append(a); } template void Vec::append(const Vec& w) { long len = length(); long init = MaxLength(); long src_len = w.length(); AllocateTo(len+src_len); const T *src = w.elts(); T *dst = elts(); // NOTE: these assignments could throw if (len+src_len <= init) { long i; for (i = 0; i < src_len; i++) dst[i+len] = src[i]; } else { long i; for (i = 0; i < init-len; i++) dst[i+len] = src[i]; Init(src_len+len, src+init-len); } AdjustLength(len+src_len); } template void append(Vec& v, const Vec& w) { v.append(w); } template NTL_SNS istream & operator>>(NTL_SNS istream& s, Vec& a) { Vec ibuf; long c; long n; if (!s) NTL_INPUT_ERROR(s, "bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } if (c != '[') { NTL_INPUT_ERROR(s, "bad vector input"); } n = 0; ibuf.SetLength(0); s.get(); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } while (c != ']' && !IsEOFChar(c)) { if (n % NTL_VectorInputBlock == 0) ibuf.SetMaxLength(n + NTL_VectorInputBlock); n++; ibuf.SetLength(n); if (!(s >> ibuf[n-1])) NTL_INPUT_ERROR(s, "bad vector input"); c = s.peek(); while (IsWhiteSpace(c)) { s.get(); c = s.peek(); } } if (IsEOFChar(c)) NTL_INPUT_ERROR(s, "bad vector input"); s.get(); a = ibuf; return s; } template NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const Vec& a) { long i, n; n = a.length(); s << '['; for (i = 0; i < n; i++) { s << a[i]; if (i < n-1) s << " "; } s << ']'; return s; } template long operator==(const Vec& a, const Vec& b) { long n = a.length(); if (b.length() != n) return 0; const T* ap = a.elts(); const T* bp = b.elts(); long i; for (i = 0; i < n; i++) if (ap[i] != bp[i]) return 0; return 1; } template long operator!=(const Vec& a, const Vec& b) { return !(a == b); } // conversions template void conv(Vec& x, const Vec& a) { long n = a.length(); x.SetLength(n); for (long i = 0; i < n; i++) conv(x[i], a[i]); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_GF2EX_long.h0000644417616742025610000000041114064716022021247 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_GF2EX_long__H #define NTL_pair_GF2EX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_GF2EX_long; typedef Vec vec_pair_GF2EX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_GF2X_long.h0000644417616742025610000000040014064716022021140 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_GF2X_long__H #define NTL_pair_GF2X_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_GF2X_long; typedef Vec vec_pair_GF2X_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_ZZX_long.h0000644417616742025610000000037114064716022021134 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_ZZX_long__H #define NTL_pair_ZZX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_ZZX_long; typedef Vec vec_pair_ZZX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_ZZ_pEX_long.h0000644417616742025610000000036714064716022021565 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_ZZ_pEX_long__H #define NTL_pair_ZZ_pEX_long__H #include #include NTL_OPEN_NNS typedef Pair pair_ZZ_pEX_long; typedef Vec vec_pair_ZZ_pEX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_ZZ_pX_long.h0000644417616742025610000000040714064716022021453 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_ZZ_pX_long__H #define NTL_pair_ZZ_pX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_ZZ_pX_long; typedef Vec vec_pair_ZZ_pX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_lzz_pEX_long.h0000644417616742025610000000037014064716022022033 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_zz_pEX_long__H #define NTL_pair_zz_pEX_long__H #include #include NTL_OPEN_NNS typedef Pair pair_zz_pEX_long; typedef Vec vec_pair_zz_pEX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pair_lzz_pX_long.h0000644417616742025610000000041014064716022021721 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pair_zz_pX_long__H #define NTL_pair_zz_pX_long__H #include #include #include NTL_OPEN_NNS typedef Pair pair_zz_pX_long; typedef Vec vec_pair_zz_pX_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/quad_float.h0000644417616742025610000002360214064716022020530 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_quad_float__H #define NTL_quad_float__H // The quad_float module is derived from the doubledouble // library originally developed by Keith Briggs: // http://keithbriggs.info/doubledouble.html // I attach the original copyright notice. /* Copyright (C) 1997 Keith Martin Briggs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include NTL_OPEN_NNS class quad_float { public: double hi, lo; // Constructors quad_float() : hi(0), lo(0) {} explicit quad_float(double a) : hi(0), lo(0) { *this = a; } inline quad_float& operator=(double x); static NTL_CHEAP_THREAD_LOCAL long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } quad_float(double x, double y) : hi(x), lo(y) { } // internal use only // FIXME: add a special argument to this to make it more "internal" }; // end class quad_float NTL_DECLARE_RELOCATABLE((quad_float*)) #if (NTL_BITS_PER_LONG < NTL_DOUBLE_PRECISION) // FIXME: we could make this <=, and even BPL <= DP+1 for // conversions from signed long...but this is mainly academic inline quad_float to_quad_float(long n) { return quad_float(n, 0); } inline quad_float to_quad_float(unsigned long n) { return quad_float(n, 0); } #else quad_float to_quad_float(long n); quad_float to_quad_float(unsigned long n); #endif void quad_float_normalize(quad_float& z, const double& xhi, const double& xlo); void quad_float_in_place_add(quad_float& x, const quad_float& y); void quad_float_in_place_sub(quad_float& x, const quad_float& y); void quad_float_in_place_mul(quad_float& x, const quad_float& y); void quad_float_in_place_div(quad_float& x, const quad_float& y); void quad_float_in_place_negate(quad_float& x); void quad_float_in_place_sqrt(quad_float& y, double& c_ref); void quad_float_PrecisionOK(long&, const double&); #if (NTL_BITS_PER_INT < NTL_DOUBLE_PRECISION) inline quad_float to_quad_float(int n) { return quad_float(n, 0); } inline quad_float to_quad_float(unsigned int n) { return quad_float(n, 0); } #else inline quad_float to_quad_float(int n) { return to_quad_float(long(n)); } inline quad_float to_quad_float(unsigned int n) { return to_quad_float((unsigned long) n); } #endif // NOTE: for extended precision platforms, the call to TrueDouble // should remove it inline quad_float to_quad_float(double x) { return quad_float(TrueDouble(x), 0); } inline quad_float to_quad_float(float x) { return to_quad_float(double(x)); } inline quad_float& quad_float::operator=(double x) { *this = to_quad_float(x); return *this; } inline quad_float& operator+= (quad_float& x, const quad_float& y) { quad_float_in_place_add(x, y); return x; } inline quad_float& operator-= (quad_float& x, const quad_float& y) { quad_float_in_place_sub(x, y); return x; } inline quad_float& operator*= (quad_float& x, const quad_float& y) { quad_float_in_place_mul(x, y); return x; } inline quad_float& operator/= (quad_float& x, const quad_float& y) { quad_float_in_place_div(x, y); return x; } inline quad_float operator-(const quad_float& x) { quad_float xx = x; quad_float_in_place_negate(xx); return xx; } inline quad_float operator+(const quad_float& x, const quad_float& y) { quad_float xx = x; xx += y; return xx; } inline quad_float operator-(const quad_float& x, const quad_float& y) { quad_float xx = x; xx -= y; return xx; } inline quad_float operator*(const quad_float& x, const quad_float& y) { quad_float xx = x; xx *= y; return xx; } inline quad_float operator/(const quad_float& x, const quad_float& y) { quad_float xx = x; xx /= y; return xx; } inline quad_float operator+(const quad_float& x, double y ) { return x + to_quad_float(y); } inline quad_float operator+(double x, const quad_float& y) { return to_quad_float(x) + y; } inline quad_float operator-(const quad_float& x, double y ) { return x - to_quad_float(y); } inline quad_float operator-(double x, const quad_float& y) { return to_quad_float(x) - y; } inline quad_float operator*(const quad_float& x, double y ) { return x * to_quad_float(y); } inline quad_float operator*(double x, const quad_float& y) { return to_quad_float(x) * y; } inline quad_float operator/(const quad_float& x, double y ) { return x / to_quad_float(y); } inline quad_float operator/(double x, const quad_float& y) { return to_quad_float(x) / y; } inline quad_float& operator += (quad_float& x, double y) { x += to_quad_float(y); return x; } inline quad_float& operator-= (quad_float& x, double y) { x -= to_quad_float(y); return x; } inline quad_float& operator*= (quad_float& x, double y) { x *= to_quad_float(y); return x; } inline quad_float& operator/= (quad_float& x, double y) { x /= to_quad_float(y); return x; } inline quad_float& operator++(quad_float& a) { a += 1.0; return a; } inline void operator++(quad_float& a, int) { a += 1.0; } inline quad_float& operator--(quad_float& a) { a -= 1.0; return a; } inline void operator--(quad_float& a, int) { a -= 1.0; } long operator> (const quad_float& x, const quad_float& y); long operator>=(const quad_float& x, const quad_float& y); long operator< (const quad_float& x, const quad_float& y); long operator<=(const quad_float& x, const quad_float& y); long operator==(const quad_float& x, const quad_float& y); long operator!=(const quad_float& x, const quad_float& y); inline long operator> (const quad_float& x, double y) { return x > to_quad_float(y); } inline long operator> (double x, const quad_float& y) { return to_quad_float(x) > y; } inline long operator>=(const quad_float& x, double y) { return x >= to_quad_float(y); } inline long operator>=(double x, const quad_float& y) { return to_quad_float(x) >= y; } inline long operator< (const quad_float& x, double y) { return x < to_quad_float(y); } inline long operator< (double x, const quad_float& y) { return to_quad_float(x) < y; } inline long operator<=(const quad_float& x, double y) { return x <= to_quad_float(y); } inline long operator<=(double x, const quad_float& y) { return to_quad_float(x) <= y; } inline long operator!=(const quad_float& x, double y) { return x != to_quad_float(y); } inline long operator!=(double x, const quad_float& y) { return to_quad_float(x) != y; } inline long operator==(const quad_float& x, double y) { return x == to_quad_float(y); } inline long operator==(double x, const quad_float& y) { return to_quad_float(x) == y; } inline long sign(const quad_float& x){ if (x.hi>0.0) return 1; else if (x.hi<0.0) return -1; else return 0; } long compare(const quad_float&, const quad_float&); inline long compare(const quad_float& x, double y) { return compare(x, to_quad_float(y)); } inline long compare(double x, const quad_float& y) { return compare(to_quad_float(x), y); } NTL_SNS istream& operator >> (NTL_SNS istream&, quad_float&); NTL_SNS ostream& operator << (NTL_SNS ostream&, const quad_float&); quad_float sqrt(const quad_float&); quad_float floor(const quad_float&); quad_float ceil(const quad_float&); quad_float trunc(const quad_float&); quad_float fabs(const quad_float&); void power(quad_float&, const quad_float&, long); inline quad_float power(const quad_float& x, long e) { quad_float z; power(z, x, e); return z; } void power2(quad_float&, long); inline quad_float power2_quad_float(long e) { quad_float z; power2(z, e); return z; } long to_long(const quad_float&); inline int to_int(const quad_float& x) { return to_int(to_long(x)); } inline double to_double(const quad_float& x) { return x.hi; } inline float to_float(const quad_float& x) { return float(x.hi); } inline void conv(quad_float& x, int a) { x = to_quad_float(a); } inline void conv(quad_float& x, long a) { x = to_quad_float(a); } inline void conv(quad_float& x, unsigned int a) { x = to_quad_float(a); } inline void conv(quad_float& x, unsigned long a) { x = to_quad_float(a); } inline void conv(quad_float& x, float a) { x = to_quad_float(a); } inline void conv(quad_float& x, double a) { x = to_quad_float(a); } inline void conv(long& x, const quad_float& a) { x = to_long(a); } inline void conv(int& x, const quad_float& a) { x = to_int(a); } inline void conv(double& x, const quad_float& a) { x = to_double(a); } inline void conv(float& x, const quad_float& a) { x = to_float(a); } void conv(quad_float&, const ZZ&); inline quad_float to_quad_float(const ZZ& x) { quad_float z; conv(z, x); return z; } void conv(ZZ&, const quad_float&); inline ZZ to_ZZ(const quad_float& a) { ZZ x; conv(x, a); NTL_OPT_RETURN(ZZ, x); } inline void conv(quad_float& x, const quad_float& a) { x = a; } inline quad_float to_quad_float(const quad_float& a) { return a; } inline quad_float to_quad_float(const char *s) { quad_float res; conv(res, s); return res; } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const quad_float& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const quad_float& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ long IsFinite(quad_float *x); quad_float ldexp(const quad_float& x, long exp); quad_float exp(const quad_float& x); quad_float log(const quad_float& x); void random(quad_float& x); quad_float random_quad_float(); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/tools.h0000644417616742025610000007210314064716022017551 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_tools__H #define NTL_tools__H //#define NTL_TEST_EXCEPTIONS #include #include #include #include #include #include #include #include #include #include #ifdef NTL_SAFE_VECTORS #include #endif #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK)) #include #endif #define NTL_SNS std :: #define NTL_USE_SNS using namespace std; #define NTL_IMPORT_FROM_STD \ using NTL_SNS abs; \ using NTL_SNS ceil; \ using NTL_SNS exp; \ using NTL_SNS fabs; \ using NTL_SNS floor; \ using NTL_SNS ldexp; \ using NTL_SNS log; \ using NTL_SNS sqrt; \ using NTL_SNS ostream; \ using NTL_SNS istream; \ using NTL_SNS cerr; \ using NTL_SNS ifstream; \ using NTL_SNS ofstream; #ifndef NTL_LEGACY_NO_NAMESPACE // This wraps NTL in the NTL namespace. // This is the current default. #define NTL_NAMESPACE NTL #define NTL_OPEN_NNS namespace NTL_NAMESPACE { #define NTL_CLOSE_NNS } #define NTL_USE_NNS using namespace NTL_NAMESPACE; #define NTL_NNS NTL_NAMESPACE :: // To make things work, we have to apply using declarations of all std // functions that are both overloaded by NTL and are used in // the implementation of NTL. #define NTL_START_IMPL NTL_OPEN_NNS NTL_IMPORT_FROM_STD #define NTL_END_IMPL NTL_CLOSE_NNS #else // This puts NTL in the global namespace. // Provided only for backward compatibility. #define NTL_NAMESPACE #define NTL_OPEN_NNS #define NTL_CLOSE_NNS #define NTL_USE_NNS #define NTL_NNS #define NTL_START_IMPL NTL_IMPORT_FROM_STD #define NTL_END_IMPL #endif #define NTL_CLIENT NTL_USE_SNS NTL_USE_NNS double _ntl_GetTime(); unsigned long _ntl_GetPID(); typedef unsigned long _ntl_ulong; typedef _ntl_ulong *_ntl_ulong_ptr; // I made these have "obscure" names to avoid conflict with // (non-standard but common) definitions in standard headers. // Putting u_long inside namespace NTL only tends to creates ambiguities, // for no good reason. NTL_OPEN_NNS #ifndef NTL_LEGACY_INPUT_ERROR // this newer version is more in line with wider C++ // practice, setting the "fail bit" of an input stream // when an error is encounted. This is now the default in NTL #define NTL_INPUT_ERROR(s, msg) \ do {\ s.setstate(NTL_SNS ios::failbit);\ return s;\ } while (0)\ #else // this version provides full backward compatibility, // raising an error on ill-formed or missing input #define NTL_INPUT_ERROR(s, msg) \ do {\ InputError(msg);\ } while (0)\ #endif #define NTL_INPUT_CHECK_ERR(stmt) \ do {\ if (!(stmt)) InputError("bad input\n");\ } while (0)\ #define NTL_INPUT_CHECK_RET(s, stmt) \ do {\ if (!(stmt)) { s.setstate(NTL_SNS ios::failbit); return s; }\ } while (0)\ #define NTL_FILE_THRESH (1e12) // threshold in KB for switching to external storage of certain tables struct INIT_SIZE_STRUCT { }; const INIT_SIZE_STRUCT INIT_SIZE = INIT_SIZE_STRUCT(); typedef const INIT_SIZE_STRUCT& INIT_SIZE_TYPE; struct INIT_VAL_STRUCT { }; const INIT_VAL_STRUCT INIT_VAL = INIT_VAL_STRUCT(); typedef const INIT_VAL_STRUCT& INIT_VAL_TYPE; struct INIT_TRANS_STRUCT { }; const INIT_TRANS_STRUCT INIT_TRANS = INIT_TRANS_STRUCT(); typedef const INIT_TRANS_STRUCT& INIT_TRANS_TYPE; struct INIT_LOOP_HOLE_STRUCT { }; const INIT_LOOP_HOLE_STRUCT INIT_LOOP_HOLE = INIT_LOOP_HOLE_STRUCT(); typedef const INIT_LOOP_HOLE_STRUCT& INIT_LOOP_HOLE_TYPE; struct INIT_FFT_STRUCT { }; const INIT_FFT_STRUCT INIT_FFT = INIT_FFT_STRUCT(); typedef const INIT_FFT_STRUCT& INIT_FFT_TYPE; struct INIT_USER_FFT_STRUCT { }; const INIT_USER_FFT_STRUCT INIT_USER_FFT = INIT_USER_FFT_STRUCT(); typedef const INIT_USER_FFT_STRUCT& INIT_USER_FFT_TYPE; struct INIT_NO_ALLOC_STRUCT { }; const INIT_NO_ALLOC_STRUCT INIT_NO_ALLOC = INIT_NO_ALLOC_STRUCT(); typedef const INIT_NO_ALLOC_STRUCT& INIT_NO_ALLOC_TYPE; struct INIT_ALLOC_STRUCT { }; const INIT_ALLOC_STRUCT INIT_ALLOC = INIT_ALLOC_STRUCT(); typedef const INIT_ALLOC_STRUCT& INIT_ALLOC_TYPE; struct INIT_MONO_STRUCT { }; const INIT_MONO_STRUCT INIT_MONO = INIT_MONO_STRUCT(); typedef const INIT_MONO_STRUCT& INIT_MONO_TYPE; #ifdef NTL_NO_INIT_TRANS #define NTL_OPT_RETURN(t, x) return x #else #define NTL_OPT_RETURN(t, x) return t(x, INIT_TRANS) #endif #ifndef NTL_NO_MIN_MAX inline int min(int a, int b) { return (a < b) ? a : b; } inline int max(int a, int b) { return (a < b) ? b : a; } inline long min(long a, long b) { return (a < b) ? a : b; } inline long max(long a, long b) { return (a < b) ? b : a; } inline long min(int a, long b) { return (a < b) ? long(a) : b; } inline long max(int a, long b) { return (a < b) ? b : long(a); } inline long min(long a, int b) { return (a < b) ? a : long(b); } inline long max(long a, int b) { return (a < b) ? long(b) : a; } inline unsigned int min(unsigned int a, unsigned int b) { return (a < b) ? a : b; } inline unsigned int max(unsigned int a, unsigned int b) { return (a < b) ? b : a; } inline unsigned long min(unsigned long a, unsigned long b) { return (a < b) ? a : b; } inline unsigned long max(unsigned long a, unsigned long b) { return (a < b) ? b : a; } inline unsigned long min(unsigned int a, unsigned long b) { return (a < b) ? (unsigned long)(a) : b; } inline unsigned long max(unsigned int a, unsigned long b) { return (a < b) ? b : (unsigned long)(a); } inline unsigned long min(unsigned long a, unsigned int b) { return (a < b) ? a : (unsigned long)(b); } inline unsigned long max(unsigned long a, unsigned int b) { return (a < b) ? (unsigned long)(b) : a; } #endif // NOTE: these are here for historical reasons, so I'll leave them // Since it is likely to lead to ambiguities with std::swap, // I am not defining any more of these. inline void swap(long& a, long& b) { long t; t = a; a = b; b = t; } inline void swap(int& a, int& b) { int t; t = a; a = b; b = t; } // some convenience casting routines: inline unsigned long cast_unsigned(long a) { return (unsigned long) a; } inline unsigned int cast_unsigned(int a) { return (unsigned int) a; } // these routines respect the NTL_CLEAN_INT flag: if set, // they use code that is guaranteed to work, under the // assumption that signed integers are two's complement. // A good compiler should optimize it all away and generate // the same code in either case (tested on gcc, clang, icc, msvc++). // This is really an academic exercise... #ifdef NTL_CLEAN_INT inline long cast_signed(unsigned long a) { return NTL_ULONG_TO_LONG(a); } inline int cast_signed(unsigned int a) { return NTL_UINT_TO_INT(a); } #else inline long cast_signed(unsigned long a) { return long(a); } inline int cast_signed(unsigned int a) { return int(a); } #endif inline void conv(int& x, int a) { x = a; } inline void conv(int& x, long a) { unsigned y = (unsigned) a; x = cast_signed(y); } inline void conv(int& x, float a) { x = int(NTL_SNS floor(double(a))); } inline void conv(int& x, double a) { x = int(NTL_SNS floor(a)); } inline void conv(int& x, unsigned a) { x = cast_signed(a); } inline void conv(int& x, unsigned long a) { unsigned y = (unsigned) a; x = cast_signed(y); } inline int to_int(int a) { return a; } inline int to_int(long a) { unsigned y = (unsigned) a; return cast_signed(y); } inline int to_int(float a) { return int(NTL_SNS floor(double(a))); } inline int to_int(double a) { return int(NTL_SNS floor(a)); } inline int to_int(unsigned a) { return cast_signed(a); } inline int to_int(unsigned long a) { unsigned y = (unsigned) a; return cast_signed(y); } inline void conv(long& x, int a) { x = a; } inline void conv(long& x, long a) { x = a; } inline void conv(long& x, float a) { x = long(NTL_SNS floor(double(a))); } inline void conv(long& x, double a) { x = long(NTL_SNS floor(a)); } inline void conv(long& x, unsigned a) { unsigned long y = a; x = cast_signed(y); } inline void conv(long& x, unsigned long a) { x = cast_signed(a); } inline long to_long(int a) { return a; } inline long to_long(long a) { return a; } inline long to_long(float a) { return long(NTL_SNS floor(double(a))); } inline long to_long(double a) { return long(NTL_SNS floor(a)); } inline long to_long(unsigned a) { unsigned long y = a; return cast_signed(y); } inline long to_long(unsigned long a) { return cast_signed(a); } inline void conv(float& x, int a) { x = float(a); } inline void conv(float& x, long a) { x = float(a); } inline void conv(float& x, unsigned a) { x = float(a); } inline void conv(float& x, unsigned long a) { x = float(a); } inline void conv(float& x, float a) { x = a; } inline void conv(float& x, double a) { x = float(a); } inline float to_float(int a) { return float(a); } inline float to_float(long a) { return float(a); } inline float to_float(unsigned a) { return float(a); } inline float to_float(unsigned long a) { return float(a); } inline float to_float(float a) { return a; } inline float to_float(double a) { return float(a); } inline void conv(double& x, int a) { x = double(a); } inline void conv(double& x, long a) { x = double(a); } inline void conv(double& x, unsigned a) { x = double(a); } inline void conv(double& x, unsigned long a) { x = double(a); } inline void conv(double& x, float a) { x = double(a); } inline void conv(double& x, double a) { x = a; } inline double to_double(int a) { return double(a); } inline double to_double(long a) { return double(a); } inline double to_double(unsigned a) { return double(a); } inline double to_double(unsigned long a) { return double(a); } inline double to_double(float a) { return double(a); } inline double to_double(double a) { return a; } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, int a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, long a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, unsigned a) { x = a; } inline void conv(unsigned int& x, unsigned long a) { x = ((unsigned int)(a)); } inline void conv(unsigned int& x, float a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned int& x, double a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned long& x, int a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, long a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, unsigned a) { x = ((unsigned long)(a)); } inline void conv(unsigned long& x, unsigned long a) { x = a; } inline void conv(unsigned long& x, float a) { x = ((unsigned int) to_long(a)); } inline void conv(unsigned long& x, double a) { x = ((unsigned int) to_long(a)); } long SkipWhiteSpace(NTL_SNS istream& s); long IsWhiteSpace(long c); long IsEOFChar(long c); long CharToIntVal(long c); char IntValToChar(long a); inline double GetTime() { return _ntl_GetTime(); } inline unsigned long GetPID() { return _ntl_GetPID(); } inline double GetWallTime() { return _ntl_GetWallTime(); } inline long IsFinite(double *p) { return _ntl_IsFinite(p); } #if (NTL_EXT_DOUBLE) inline void ForceToMem(double *p) { _ntl_ForceToMem(p); } #else inline void ForceToMem(double *p) { } #endif inline double TrueDouble(double x) { ForceToMem(&x); return x; } void PrintTime(NTL_SNS ostream& s, double t); #if (defined(__GNUC__) && (__GNUC__ >= 4)) // on relative modern versions of gcc, we can // decalare "restricted" pointers in C++ // we also can use __attribute__((always_inline)) #define NTL_RESTRICT __restrict #define NTL_ALWAYS_INLINE __attribute__((always_inline)) #else #define NTL_RESTRICT #define NTL_ALWAYS_INLINE #endif // A very lightly wrapped pointer than does nothing more than provide // auto cleanup in a destructor. Use the UniquePtr class (in SmartPtr.h) // for a class with more safety and convenience features. // This class is easiest to use to retrofit older code with RAII // semantics. // A call to Deleter::apply should free the pointed-to storage template class WrappedPtr { private: WrappedPtr(const WrappedPtr&); // disable void operator=(const WrappedPtr&); // disable public: typedef T * raw_ptr; raw_ptr rep; WrappedPtr() : rep(0) { } void operator=(const raw_ptr& _rep) { rep = _rep; } ~WrappedPtr() { if (rep) Deleter::apply(rep); } operator const raw_ptr& () const { return rep; } operator raw_ptr& () { return rep; } const raw_ptr* operator&() const { return &rep; } raw_ptr* operator&() { return &rep; } void kill() { if (rep) { Deleter::apply(rep); rep = 0; } } void swap(WrappedPtr& other) { _ntl_swap(rep, other.rep); } void move(WrappedPtr& other) { WrappedPtr tmp; tmp.swap(other); tmp.swap(*this); } }; template void swap(WrappedPtr& x, WrappedPtr& y) { x.swap(y); } // Error Handling class ErrorObject : public NTL_SNS runtime_error { public: ErrorObject(const char *msg) : runtime_error(msg) { } }; class LogicErrorObject : public ErrorObject { public: LogicErrorObject(const char *msg) : ErrorObject(msg) { } }; class ArithmeticErrorObject : public ErrorObject { public: ArithmeticErrorObject(const char *msg) : ErrorObject(msg) { } }; class ResourceErrorObject : public ErrorObject { public: ResourceErrorObject(const char *msg) : ErrorObject(msg) { } }; class FileErrorObject : public ErrorObject { public: FileErrorObject(const char *msg) : ErrorObject(msg) { } }; class InputErrorObject : public ErrorObject { public: InputErrorObject(const char *msg) : ErrorObject(msg) { } }; extern NTL_CHEAP_THREAD_LOCAL void (*ErrorCallback)(); extern NTL_CHEAP_THREAD_LOCAL void (*ErrorMsgCallback)(const char *); void TerminalError(const char *s); #ifdef NTL_EXCEPTIONS inline void MemoryError() { throw NTL_SNS bad_alloc(); } inline void Error(const char *msg) { throw ErrorObject(msg); } inline void LogicError(const char *msg) { throw LogicErrorObject(msg); } inline void ArithmeticError(const char *msg) { throw ArithmeticErrorObject(msg); } inline void InvModError(const char *msg) { throw ArithmeticErrorObject(msg); } inline void ResourceError(const char *msg) { throw ResourceErrorObject(msg); } inline void FileError(const char *msg) { throw FileErrorObject(msg); } inline void InputError(const char *msg) { throw InputErrorObject(msg); } #else inline void MemoryError() { TerminalError("out of memory"); } inline void Error(const char *msg) { TerminalError(msg); } inline void LogicError(const char *msg) { TerminalError(msg); } inline void ArithmeticError(const char *msg) { TerminalError(msg); } inline void InvModError(const char *msg) { TerminalError(msg); } inline void ResourceError(const char *msg) { TerminalError(msg); } inline void FileError(const char *msg) { TerminalError(msg); } inline void InputError(const char *msg) { TerminalError(msg); } #endif #ifdef NTL_EXCEPTIONS template < typename F > class scope_guard { typename std::remove_reference::type f; bool active; const char *info; public: scope_guard(F&& _f, const char *_info) : f(std::forward(_f)), active(true), info(_info) { } ~scope_guard() { if (active) { #ifdef NTL_TEST_EXCEPTIONS NTL_SNS cerr << "*** ACTIVE SCOPE GUARD TRIGGERED: " << info << "\n"; #endif f(); } } void relax() { active = false; } }; struct scope_guard_builder { const char *info; explicit scope_guard_builder(const char *_info) : info(_info) { } }; template < typename F > scope_guard operator+(scope_guard_builder b, F&& f) { return scope_guard(std::forward(f), b.info); } #define NTL_SCOPE(var) auto var = \ scope_guard_builder(__FILE__ ":" NTL_STRINGIFY(__LINE__)) + [&] #else class DummyScopeGuard { bool active; public: DummyScopeGuard() : active(true) { } ~DummyScopeGuard() { if (active) TerminalError("unexpected exception"); } void relax() { active = false; } }; #define NTL_SCOPE(var) DummyScopeGuard var; if (false) #endif #define NTL_DETAILS_PTHREAD NTL_NNS details_pthread #if (defined(NTL_THREADS) && defined(NTL_TLS_HACK)) // NOTE: All of this TLS code is replicated in CheckThreads.cpp. namespace details_pthread { struct Node { Node *next; Node() : next(0) { } virtual ~Node() { } }; template struct DerivedNode : Node { T t; template DerivedNode(Args&&... args) : t(std::forward(args)...) { } }; inline void delete_node(Node *p) noexcept { delete p; } // an exception here would likely lead to a complete mess... // the noexcept specification should force an immediate termination inline void delete_list(void *vp) { Node *p = (Node *) vp; while (p) { Node *tmp = p; p = p->next; delete_node(tmp); } } using namespace std; // I'm not sure if pthread stuff might be placed in namespace std struct key_wrapper { pthread_key_t key; key_wrapper(void (*destructor)(void*)) { if (pthread_key_create(&key, destructor)) ResourceError("pthread_key_create failed"); } }; inline void push_node(Node *p) // this pushes a new node to the front to the list // of objects that need to be deleted { if (!p) MemoryError(); static key_wrapper wkey(delete_list); // This relies on C++11 thread-safe static initialization. // It also relies on the guarantee that there is just one // global key (this requirement is only needed to // limit the number of keys, not for correctness). p->next = (Node *) pthread_getspecific(wkey.key); if (pthread_setspecific(wkey.key, p)) { delete_node(p); ResourceError("pthread_setspecific failed"); } } } #define NTL_TLS_LOCAL_INIT(type, var, init) \ static NTL_CHEAP_THREAD_LOCAL NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr_ ## var = 0; \ NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr_ ## var; \ if (!_ntl_hidden_variable_tls_local_ptr1_ ## var) { \ NTL_DETAILS_PTHREAD::DerivedNode *_ntl_hidden_variable_tls_local_ptr2_ ## var = NTL_NEW_OP NTL_DETAILS_PTHREAD::DerivedNode init; \ NTL_DETAILS_PTHREAD::push_node(_ntl_hidden_variable_tls_local_ptr2_ ## var); \ _ntl_hidden_variable_tls_local_ptr1_ ## var = _ntl_hidden_variable_tls_local_ptr2_ ## var; \ _ntl_hidden_variable_tls_local_ptr_ ## var = _ntl_hidden_variable_tls_local_ptr1_ ## var; \ } \ type &var = _ntl_hidden_variable_tls_local_ptr1_ ## var->t \ #else // NOTE: this definition of NTL_TLS_LOCAL_INIT ensures that var names // a local reference, regardless of the implementation #define NTL_TLS_LOCAL_INIT(type,var,init) \ static NTL_THREAD_LOCAL type _ntl_hidden_variable_tls_local ## var init; \ type &var = _ntl_hidden_variable_tls_local ## var #endif #define NTL_EMPTY_ARG #define NTL_TLS_LOCAL(type,var) NTL_TLS_LOCAL_INIT(type,var,NTL_EMPTY_ARG) #define NTL_TLS_GLOBAL_DECL_INIT(type,var,init) \ typedef type _ntl_hidden_typedef_tls_access_ ## var; \ static inline \ type& _ntl_hidden_function_tls_access_ ## var() { \ NTL_TLS_LOCAL_INIT(type,var,init); \ return var; \ } \ #define NTL_TLS_GLOBAL_DECL(type,var) NTL_TLS_GLOBAL_DECL_INIT(type,var,NTL_EMPTY_ARG) #define NTL_TLS_GLOBAL_ACCESS(var) \ _ntl_hidden_typedef_tls_access_ ## var & var = _ntl_hidden_function_tls_access_ ## var() // ************************************************************** // Following is code for "long long" arithmetic that can // be implemented using NTL_ULL_TYPE or using assembly. // I have found that the assembly can be a bit faster. // For now, this code is only available if NTL_HAVE_LL_TYPE // is defined. This could change. In any case, this provides // a cleaner interface and might eventually allow for // implementation on systems that don't provide a long long type. // ************************************************************** #ifdef NTL_HAVE_LL_TYPE #if (!defined(NTL_DISABLE_LL_ASM) \ && defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__clang__) \ && defined (__x86_64__) && NTL_BITS_PER_LONG == 64) // NOTE: clang's and icc's inline asm code gen is pretty bad, so // we don't even try. // FIXME: probably, this should all be properly tested for speed (and correctness) // using the Wizard. struct ll_type { unsigned long hi, lo; }; inline void ll_mul_add(ll_type& x, unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ( "mulq %[b] \n\t" "addq %[lo],%[xlo] \n\t" "adcq %[hi],%[xhi]" : [lo] "=a" (lo), [hi] "=d" (hi), [xhi] "+r" (x.hi), [xlo] "+r" (x.lo) : [a] "%[lo]" (a), [b] "rm" (b) : "cc" ); } inline void ll_imul_add(ll_type& x, unsigned long a, unsigned long b) { unsigned long hi, lo; __asm__ ( "imulq %[b] \n\t" "addq %[lo],%[xlo] \n\t" "adcq %[hi],%[xhi]" : [lo] "=a" (lo), [hi] "=d" (hi), [xhi] "+r" (x.hi), [xlo] "+r" (x.lo) : [a] "%[lo]" (a), [b] "rm" (b) : "cc" ); } inline void ll_mul(ll_type& x, unsigned long a, unsigned long b) { __asm__ ( "mulq %[b]" : [lo] "=a" (x.lo), [hi] "=d" (x.hi) : [a] "%[lo]" (a), [b] "rm" (b) : "cc" ); } inline void ll_imul(ll_type& x, unsigned long a, unsigned long b) { __asm__ ( "imulq %[b]" : [lo] "=a" (x.lo), [hi] "=d" (x.hi) : [a] "%[lo]" (a), [b] "rm" (b) : "cc" ); } inline void ll_add(ll_type& x, unsigned long a) { __asm__ ( "addq %[a],%[xlo] \n\t" "adcq %[z],%[xhi]" : [xhi] "+r" (x.hi), [xlo] "+r" (x.lo) : [a] "rm" (a), [z] "i" (0) : "cc" ); } inline void ll_add(ll_type& x, const ll_type& a) { __asm__ ( "addq %[alo],%[xlo] \n\t" "adcq %[ahi],%[xhi]" : [xhi] "+r" (x.hi), [xlo] "+r" (x.lo) : [ahi] "rm" (a.hi), [alo] "rm" (a.lo) : "cc" ); } // NOTE: an optimizing compiler will remove the conditional. // The alternative would be to make a specialization for shamt=0. // Unfortunately, this is impossible to do across a wide range // of compilers and still maintain internal linkage --- it is not // allowed to include static spec in the specialization (new compilers // will complain) and without it, some older compilers will generate // an external symbol. In fact, NTL currently never calls // this with shamt=0, so it is all rather academic...but I want to // keep this general for future use. // NOTE: this implementation assumes that shamt is in the range // 0..NTL_BITS_PER_LONG-1 #if 1 // The shrd instruction can be very slow on some // machines. Two shifts is usually just as good. template unsigned long ll_rshift_get_lo(ll_type x) { unsigned long res; if (shamt) res = (x.lo >> shamt) | (x.hi << (NTL_BITS_PER_LONG-shamt)); else res = x.lo; return res; } #else template unsigned long ll_rshift_get_lo(ll_type x) { if (shamt) { __asm__ ( "shrdq %[shamt],%[hi],%[lo]" : [lo] "+r" (x.lo) : [shamt] "i" (shamt), [hi] "r" (x.hi) : "cc" ); } return x.lo; } #endif inline unsigned long ll_get_lo(const ll_type& x) { return x.lo; } inline unsigned long ll_get_hi(const ll_type& x) { return x.hi; } inline void ll_init(ll_type& x, unsigned long a) { x.lo = a; x.hi = 0; } #else typedef NTL_ULL_TYPE ll_type; // NOTE: the following functions definitions should serve as // documentation, as well. inline void ll_mul_add(ll_type& x, unsigned long a, unsigned long b) { x += ((ll_type) a)*((ll_type) b); } // a and b should be representable as positive long's, // to allow for the most flexible implementation inline void ll_imul_add(ll_type& x, unsigned long a, unsigned long b) { x += ((ll_type) long(a))*((ll_type) long(b)); } inline void ll_mul(ll_type& x, unsigned long a, unsigned long b) { x = ((ll_type) a)*((ll_type) b); } // a and b should be representable as positive long's, // to allow for the most flexible implementation inline void ll_imul(ll_type& x, unsigned long a, unsigned long b) { x = ((ll_type) long(a))*((ll_type) long(b)); } inline void ll_add(ll_type& x, unsigned long a) { x += a; } inline void ll_add(ll_type& x, const ll_type& a) { x += a; } // NOTE: shamt must be in the range 0..NTL_BITS_PER_LONG-1 template unsigned long ll_rshift_get_lo(const ll_type& x) { return ((unsigned long) (x >> shamt)); } inline unsigned long ll_get_lo(const ll_type& x) { return ((unsigned long) x); } inline unsigned long ll_get_hi(const ll_type& x) { return ((unsigned long) (x >> NTL_BITS_PER_LONG)); } inline void ll_init(ll_type& x, unsigned long a) { x = a; } #endif inline unsigned long ll_mul_hi(unsigned long a, unsigned long b) { ll_type x; ll_mul(x, a, b); return ll_get_hi(x); } #endif #ifdef NTL_SAFE_VECTORS #define NTL_RELOC_TAG (relocatable) #define NTL_DECLARE_RELOCATABLE_WHEN(x) \ constexpr bool DeclareRelocatableType x #if (defined(NTL_HAVE_COPY_TRAITS1) || defined(NTL_WINPACK)) // This strategy is used on compilers that fully support C++11 type traits. // For some reason, is_trivially_copyable says "true" even if the class // has deleted it's copy constructor. Which means it is not copyable at all. // So I added an explicit test for is_copy_constructible. // Just to be on the safe side, I check for a trivial destructor. // This strategy is checked in the CheckCOPY_TRAITS1.cpp program. // We also use this strategy for the WINPACK distribution. // It should work on Windows with any compiler that properly supports C++11 template constexpr bool Relocate_aux_has_trivial_copy(T*) { return std::is_trivially_copyable::value && std::is_trivially_destructible::value && std::is_copy_constructible::value; } template constexpr bool Relocate_aux_has_any_copy(T*) { return std::is_copy_constructible::value; } #elif (defined(NTL_HAVE_COPY_TRAITS2)) // This strategy is needed on GCC before v5.0, as the required type // traits are not impplemented. Note that on a class with it's copy // constructors deleted, __has_trivial_copy is false on GCC before 4.9 // and true startig with 4.9. So I had to make use of SFINAE techniques // to make sure there actually is a non-deleted copy constructor. // Just to be on the safe side, I check for a trivial destructor. // This strategy is checked in the CheckCOPY_TRAITS2.cpp program. template struct Relocate_aux_Failable { typedef out Type; }; struct Relocate_aux_TwoChars { char d[2]; }; template struct Relocate_aux_has_copy { static const T *MakeT(); template // U and T are the same type static typename Relocate_aux_Failable<(bool(sizeof U(*MakeT()))), char>::Type copy(int); template static typename Relocate_aux_Failable::Type copy(...); enum { value = sizeof( copy(0) ) == 1 }; }; template constexpr bool Relocate_aux_has_trivial_copy(T*) { return __has_trivial_copy(T) && __has_trivial_destructor(T) && Relocate_aux_has_copy::value; } template constexpr bool Relocate_aux_has_any_copy(T*) { return Relocate_aux_has_copy::value; } #else #error "lacking compiler support for NTL_SAFE_VECTORS" #endif // NOTE: I've checked the correctness of the above strategies using // Godbolt's compiler explorer across a range of complilers // (clang, gcc, icc, MS). template constexpr bool DeclareRelocatableType(T*) { return Relocate_aux_has_trivial_copy((T*)0); } #else #define NTL_RELOC_TAG (true) #define NTL_DECLARE_RELOCATABLE_WHEN(x) \ inline bool DeclareRelocatableType x template inline bool DeclareRelocatableType(T*) { return true; } #endif #define NTL_DECLARE_RELOCATABLE(x) NTL_DECLARE_RELOCATABLE_WHEN(x) \ { return true; } // Examples: // NTL_DECLARE_RELOCATABLE((int*)) // NTL_DECLARE_RELOCATABLE((Foo*)) // template NTL_DECLARE_RELOCATABLE((Foo*)) #if (NTL_CXX_STANDARD >= 2011) #define NTL_DEFAULT =default; #else #define NTL_DEFAULT {} #endif // The following idea for deriving from streambuf comes from: // https://stackoverflow.com/questions/1448467/initializing-a-c-stdistringstream-from-an-in-memory-buffer/1449527#1449527 struct plain_c_string_streambuf : public std::streambuf { plain_c_string_streambuf(const char* ss) { char *s = const_cast(ss); // casting away constant should be safe here, // based of my reading of the functionality // of streambuf from the documentation at cplusplus.com. setg(s, s, s + std::strlen(s)); } }; // Generic conversion from char* or const char*. We use SFINAE // to prevent conversions from 0. template typename _ntl_enable_if<_ntl_is_char_pointer::value,void>::type conv(S& x, T y) { if (!y) InputError("bad conversion from char*"); plain_c_string_streambuf buf(y); std::istream istr(&buf); if (!(istr >> x)) InputError("bad conversion from char*"); } // new style converson function // example: ZZ x = conv(1); // note: modern C++ compilers should implemented // "named return value optimization", so the // result statement should not create a temporary template T conv(const S& a) { T x; conv(x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_GF2.h0000644417616742025610000002740114064716022017625 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_GF2__H #define NTL_vec_GF2__H #include #include NTL_OPEN_NNS // Vec is an explicit specialization of Vec. // Vec is declared, but not defined, in GF2.h, // to prevent the generic Vec from being used. template<> class Vec { public: // these should be private, but they are not WordVector rep; long _len; // length (in bits) long _maxlen; // (MaxLength << 1) | (fixed) // invariants: rep.length() "tracks" length() ( = _len) // All bits in positions >= length are zero. // Note: rep.MaxLength() may exceed the value // indicated by MaxLength(). //the following are "really" public Vec() : _len(0), _maxlen(0) {} Vec(INIT_SIZE_TYPE, long n) : _len(0), _maxlen(0) { SetLength(n); } Vec(const Vec& a) : _len(0), _maxlen(0) { *this = a; } Vec& operator=(const Vec& a); ~Vec() {} #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) Vec(Vec&& a) NTL_FAKE_NOEXCEPT : Vec() { if (a.fixed()) { *this = a; } else { rep.unpinned_move(a.rep); _len = _ntl_scalar_move(a._len); _maxlen = _ntl_scalar_move(a._maxlen); } } #ifndef NTL_DISABLE_MOVE_ASSIGN Vec& operator=(Vec&& a) NTL_FAKE_NOEXCEPT { if (fixed() || a.fixed()) { *this = a; } else { rep.unpinned_move(a.rep); _len = _ntl_scalar_move(a._len); _maxlen = _ntl_scalar_move(a._maxlen); } return *this; } #endif #endif void kill(); void SetLength(long n); void SetLength(long n, GF2 a); void SetMaxLength(long n); void FixLength(long n); void FixAtCurrentLength(); long length() const { return _len; } long MaxLength() const { return _maxlen >> 1; } long allocated() const { return rep.MaxLength() * NTL_BITS_PER_LONG; } long fixed() const { return _maxlen & 1; } Vec(Vec& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS), _len(x._len), _maxlen(x._maxlen) { } ref_GF2 operator[](long i) { #ifdef NTL_RANGE_CHECK if (i < 0 || i >= _len) LogicError("index out of range in Vec"); #endif iterator t(INIT_LOOP_HOLE, rep.elts(), i); return *t; } const GF2 operator[](long i) const { #ifdef NTL_RANGE_CHECK if (i < 0 || i >= _len) LogicError("index out of range in Vec"); #endif const_iterator t(INIT_LOOP_HOLE, rep.elts(), i); return *t; } ref_GF2 at(long i) { if (i < 0 || i >= _len) LogicError("index out of range in Vec"); iterator t(INIT_LOOP_HOLE, rep.elts(), i); return *t; } const GF2 at(long i) const { if (i < 0 || i >= _len) LogicError("index out of range in Vec"); const_iterator t(INIT_LOOP_HOLE, rep.elts(), i); return *t; } void put(long i, GF2 a) { (*this)[i] = a; } void put(long i, long a) { put(i, to_GF2(a)); } const GF2 get(long i) const { return (*this)[i]; } ref_GF2 operator()(long i) { return (*this)[i-1]; } const GF2 operator()(long i) const { return (*this)[i-1]; } void swap(Vec& y); void move(Vec& y); void append(GF2 a); void append(const Vec& w); // Some partial STL compatibility...also used // to interface with the Matrix template class typedef GF2 value_type; typedef ref_GF2 reference; typedef const GF2 const_reference; // The following makes it possible to use range-based for-loops // However, the only safe ways to use it are // for (auto x: vec) // for (auto&& x : vec) // The following: // for (const auto& x : vec) // will unfortunately allow elements of vec to be modified template // T is either unsigned long or const unsigned long struct proxy_iterator_impl { T *ptr; long idx; proxy_iterator_impl() : ptr(0), idx(0) { } proxy_iterator_impl(T *_ptr, long _idx) : ptr(_ptr), idx(_idx) { } template proxy_iterator_impl(const proxy_iterator_impl& other) { ptr = other.ptr; idx = other.idx; } void add(long x) { idx += x; } void inc() { idx++; } void dec() { idx--; } ref_GF2 make_ref_GF2() const { long q, r; _ntl_bpl_divrem(cast_unsigned(idx), q, r); return ref_GF2(INIT_LOOP_HOLE, ptr+q, r); } const GF2 make_GF2() const { long q, r; _ntl_bpl_divrem(cast_unsigned(idx), q, r); return GF2(INIT_LOOP_HOLE, (ptr[q] >> r) & 1); } long diff(const proxy_iterator_impl& other) const { return (this->idx - other.idx); } bool eq(const proxy_iterator_impl& other) const { return ptr == other.ptr && idx == other.idx; } }; struct const_proxy_iterator { proxy_iterator_impl rep; const_proxy_iterator() { } const_proxy_iterator(INIT_LOOP_HOLE_TYPE, const unsigned long *ptr, long idx) : rep(ptr, idx) { } const_proxy_iterator& operator++() { rep.inc(); return *this; } const_proxy_iterator operator++(int) { const_proxy_iterator t = *this; rep.inc(); return t; } const_proxy_iterator& operator--() { rep.dec(); return *this; } const_proxy_iterator operator--(int) { const_proxy_iterator t = *this; rep.dec(); return t; } const_proxy_iterator& operator+=(long x) { rep.add(x); return *this; } const_proxy_iterator& operator-=(long x) { rep.add(-x); return *this; } const GF2 operator*() const { return rep.make_GF2(); } const GF2 operator[](long x) const { const_proxy_iterator t = *this; t.rep.add(x); return *t; } }; typedef const_proxy_iterator const_iterator; const_iterator begin() const { return const_iterator(INIT_LOOP_HOLE, rep.elts(), 0); } const_iterator end() const { return const_iterator(INIT_LOOP_HOLE, rep.elts(), _len); } struct proxy_iterator { proxy_iterator_impl rep; proxy_iterator() { } proxy_iterator(INIT_LOOP_HOLE_TYPE, unsigned long *ptr, long idx) : rep(ptr, idx) { } proxy_iterator& operator++() { rep.inc(); return *this; } proxy_iterator operator++(int) { proxy_iterator t = *this; rep.inc(); return t; } proxy_iterator& operator--() { rep.dec(); return *this; } proxy_iterator operator--(int) { proxy_iterator t = *this; rep.dec(); return t; } proxy_iterator& operator+=(long x) { rep.add(x); return *this; } proxy_iterator& operator-=(long x) { rep.add(-x); return *this; } ref_GF2 operator*() const { return rep.make_ref_GF2(); } ref_GF2 operator[](long x) const { proxy_iterator t = *this; t.rep.add(x); return *t; } operator const_proxy_iterator() const { const_proxy_iterator t; t.rep = rep; return t; } }; typedef proxy_iterator iterator; iterator begin() { return iterator(INIT_LOOP_HOLE, rep.elts(), 0); } iterator end() { return iterator(INIT_LOOP_HOLE, rep.elts(), _len); } }; typedef Vec vec_GF2; inline bool operator==(const vec_GF2::const_proxy_iterator& a, const vec_GF2::const_proxy_iterator& b) { return a.rep.eq(b.rep); } inline bool operator!=(const vec_GF2::const_proxy_iterator& a, const vec_GF2::const_proxy_iterator& b) { return !(a == b); } inline vec_GF2::const_proxy_iterator operator+(const vec_GF2::const_proxy_iterator& a, long x) { vec_GF2::const_proxy_iterator t = a; t.rep.add(x); return t; } inline vec_GF2::const_proxy_iterator operator+(long x, const vec_GF2::const_proxy_iterator& a) { return a + x; } inline vec_GF2::const_proxy_iterator operator-(const vec_GF2::const_proxy_iterator& a, long x) { vec_GF2::const_proxy_iterator t = a; t.rep.add(-x); return t; } inline vec_GF2::const_proxy_iterator operator-(long x, const vec_GF2::const_proxy_iterator& a) { return a - x; } inline long operator-(const vec_GF2::const_proxy_iterator& a, const vec_GF2::const_proxy_iterator& b) { return a.rep.diff(b.rep); } inline bool operator==(const vec_GF2::proxy_iterator& a, const vec_GF2::proxy_iterator& b) { return a.rep.eq(b.rep); } inline bool operator!=(const vec_GF2::proxy_iterator& a, const vec_GF2::proxy_iterator& b) { return !(a == b); } inline vec_GF2::proxy_iterator operator+(const vec_GF2::proxy_iterator& a, long x) { vec_GF2::proxy_iterator t = a; t.rep.add(x); return t; } inline vec_GF2::proxy_iterator operator+(long x, const vec_GF2::proxy_iterator& a) { return a + x; } inline vec_GF2::proxy_iterator operator-(const vec_GF2::proxy_iterator& a, long x) { vec_GF2::proxy_iterator t = a; t.rep.add(-x); return t; } inline vec_GF2::proxy_iterator operator-(long x, const vec_GF2::proxy_iterator& a) { return a - x; } inline long operator-(const vec_GF2::proxy_iterator& a, const vec_GF2::proxy_iterator& b) { return a.rep.diff(b.rep); } // sepcialized conversion inline void conv(vec_GF2& x, const vec_GF2& a) { x = a; } inline void swap(vec_GF2& x, vec_GF2& y) { x.swap(y); } inline void append(vec_GF2& v, const GF2 a) { v.append(a); } inline void append(vec_GF2& v, const vec_GF2& a) { v.append(a); } long operator==(const vec_GF2& a, const vec_GF2& b); inline long operator!=(const vec_GF2& a, const vec_GF2& b) { return !(a == b); } NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const vec_GF2& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, vec_GF2& a); void shift(vec_GF2& x, const vec_GF2& a, long n); // x = a shifted n places, i.e., if l = a.length(), // x.length() = l, x[i] = a[i-n] for 0 <= i-n < l, // and x[i] = 0 for all other i such that 0 <= i < l. inline vec_GF2 shift(const vec_GF2& a, long n) { vec_GF2 x; shift(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } void reverse(vec_GF2& x, const vec_GF2& a); inline vec_GF2 reverse(const vec_GF2& a) { vec_GF2 x; reverse(x, a); NTL_OPT_RETURN(vec_GF2, x); } void random(vec_GF2& x, long n); inline vec_GF2 random_vec_GF2(long n) { vec_GF2 x; random(x, n); NTL_OPT_RETURN(vec_GF2, x); } long weight(const vec_GF2& a); void mul(vec_GF2& x, const vec_GF2& a, GF2 b); inline void mul(vec_GF2& x, GF2 a, const vec_GF2& b) { mul(x, b, a); } inline void mul(vec_GF2& x, const vec_GF2& a, long b) { mul(x, a, to_GF2(b)); } inline void mul(vec_GF2& x, long a, const vec_GF2& b) { mul(x, b, a); } void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); inline void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b) { add(x, a, b); } void clear(vec_GF2& x); inline void negate(vec_GF2& x, const vec_GF2& a) { x = a; } inline void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b) { x = to_GF2(InnerProduct(a.rep, b.rep)); } long IsZero(const vec_GF2& a); vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b); inline vec_GF2 operator-(const vec_GF2& a) { return a; } inline vec_GF2 operator*(const vec_GF2& a, GF2 b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(const vec_GF2& a, long b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(GF2 a, const vec_GF2& b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline vec_GF2 operator*(long a, const vec_GF2& b) { vec_GF2 x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2, x); } inline GF2 operator*(const vec_GF2& a, const vec_GF2& b) { return to_GF2(InnerProduct(a.rep, b.rep)); } // assignment operator notation: inline vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a) { add(x, x, a); return x; } inline vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a) { sub(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, GF2 a) { mul(x, x, a); return x; } inline vec_GF2& operator*=(vec_GF2& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_GF2& x, const vec_GF2& a, long n); inline vec_GF2 VectorCopy(const vec_GF2& a, long n) { vec_GF2 x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_GF2E.h0000644417616742025610000000526214064716022017733 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_GF2E__H #define NTL_vec_GF2E__H #include NTL_OPEN_NNS typedef Vec vec_GF2E; void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b); inline void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b) { mul(x, b, a); } void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b); inline void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b) { mul(x, b, a); } inline void mul(vec_GF2E& x, const vec_GF2E& a, long b) { mul(x, a, to_GF2(b)); } inline void mul(vec_GF2E& x, long a, const vec_GF2E& b) { mul(x, b, a); } void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); inline void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b) { add(x, a, b); } inline void negate(vec_GF2E& x, const vec_GF2E& a) { x = a; } void clear(vec_GF2E& x); void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b); void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset); long IsZero(const vec_GF2E& a); vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a); GF2E operator*(const vec_GF2E& a, const vec_GF2E& b); inline vec_GF2E operator*(const vec_GF2E& a, const GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const vec_GF2E& a, GF2 b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const vec_GF2E& a, long b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(const GF2E& a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(GF2 a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } inline vec_GF2E operator*(long a, const vec_GF2E& b) { vec_GF2E x; mul(x, a, b); NTL_OPT_RETURN(vec_GF2E, x); } // assignment operator notation: inline vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a) { add(x, x, a); return x; } inline vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a) { sub(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, GF2 a) { mul(x, x, a); return x; } inline vec_GF2E& operator*=(vec_GF2E& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n); inline vec_GF2E VectorCopy(const vec_GF2E& a, long n) { vec_GF2E x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_GF2E, x); } void random(vec_GF2E& x, long n); inline vec_GF2E random_vec_GF2E(long n) { vec_GF2E x; random(x, n); NTL_OPT_RETURN(vec_GF2E, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_GF2XVec.h0000644417616742025610000000026114064716022020406 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_GF2XVec__H #define NTL_vec_GF2XVec__H #include #include NTL_OPEN_NNS typedef Vec vec_GF2XVec; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_RR.h0000644417616742025610000000351614064716022017573 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_RR__H #define NTL_vec_RR__H #include #include NTL_OPEN_NNS typedef Vec vec_RR; void mul(vec_RR& x, const vec_RR& a, const RR& b); inline void mul(vec_RR& x, const RR& a, const vec_RR& b) { mul(x, b, a); } void mul(vec_RR& x, const vec_RR& a, double b); inline void mul(vec_RR& x, double a, const vec_RR& b) { mul(x, b, a); } void add(vec_RR& x, const vec_RR& a, const vec_RR& b); void sub(vec_RR& x, const vec_RR& a, const vec_RR& b); void clear(vec_RR& x); void negate(vec_RR& x, const vec_RR& a); void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b); long IsZero(const vec_RR& a); void VectorCopy(vec_RR& x, const vec_RR& a, long n); inline vec_RR VectorCopy(const vec_RR& a, long n) { vec_RR x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_RR, x); } vec_RR operator+(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a); inline vec_RR operator*(const vec_RR& a, const RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(const vec_RR& a, double b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(const RR& a, const vec_RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } inline vec_RR operator*(double a, const vec_RR& b) { vec_RR x; mul(x, a, b); NTL_OPT_RETURN(vec_RR, x); } RR operator*(const vec_RR& a, const vec_RR& b); // assignment operator notation: inline vec_RR& operator+=(vec_RR& x, const vec_RR& a) { add(x, x, a); return x; } inline vec_RR& operator-=(vec_RR& x, const vec_RR& a) { sub(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, const RR& a) { mul(x, x, a); return x; } inline vec_RR& operator*=(vec_RR& x, double a) { mul(x, x, a); return x; } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_ZZ.h0000644417616742025610000000350514064716022017611 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_ZZ__H #define NTL_vec_ZZ__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZ; void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b); inline void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b) { mul(x, b, a); } void mul(vec_ZZ& x, const vec_ZZ& a, long b); inline void mul(vec_ZZ& x, long a, const vec_ZZ& b) { mul(x, b, a); } void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); void clear(vec_ZZ& x); void negate(vec_ZZ& x, const vec_ZZ& a); void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b); long IsZero(const vec_ZZ& a); vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a); inline vec_ZZ operator*(const vec_ZZ& a, const ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(const vec_ZZ& a, long b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(const ZZ& a, const vec_ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } inline vec_ZZ operator*(long a, const vec_ZZ& b) { vec_ZZ x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ, x); } ZZ operator*(const vec_ZZ& a, const vec_ZZ& b); // assignment operator notation: inline vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a) { add(x, x, a); return x; } inline vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a) { sub(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a) { mul(x, x, a); return x; } inline vec_ZZ& operator*=(vec_ZZ& x, long a) { mul(x, x, a); return x; } void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n); inline vec_ZZ VectorCopy(const vec_ZZ& a, long n) { vec_ZZ x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_ZZVec.h0000644417616742025610000000024714064716022020247 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_ZZVec__H #define NTL_vec_ZZVec__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZVec; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_ZZ_p.h0000644417616742025610000000465514064716022020137 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_ZZ_p__H #define NTL_vec_ZZ_p__H #include #include NTL_OPEN_NNS typedef Vec vec_ZZ_p; // legacy conversion notation inline vec_ZZ_p to_vec_ZZ_p(const vec_ZZ& a) { vec_ZZ_p x; conv(x, a); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ to_vec_ZZ(const vec_ZZ_p& a) { vec_ZZ x; conv(x, a); NTL_OPT_RETURN(vec_ZZ, x); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b); inline void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b) { mul(x, b, a); } void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b); inline void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b) { mul(x, b, a); } void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void clear(vec_ZZ_p& x); void negate(vec_ZZ_p& x, const vec_ZZ_p& a); void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset); long IsZero(const vec_ZZ_p& a); void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n); inline vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n) { vec_ZZ_p x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ_p, x); } vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a); inline vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(const vec_ZZ_p& a, long b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } inline vec_ZZ_p operator*(long a, const vec_ZZ_p& b) { vec_ZZ_p x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_p, x); } ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b); // assignment operator notation: inline vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a) { add(x, x, a); return x; } inline vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a) { sub(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a) { mul(x, x, a); return x; } inline vec_ZZ_p& operator*=(vec_ZZ_p& x, long a) { mul(x, x, a); return x; } void random(vec_ZZ_p& x, long n); inline vec_ZZ_p random_vec_ZZ_p(long n) { vec_ZZ_p x; random(x, n); NTL_OPT_RETURN(vec_ZZ_p, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_ZZ_pE.h0000644417616742025610000000535314064716022020240 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_ZZ_pE__H #define NTL_vec_ZZ_pE__H #include NTL_OPEN_NNS typedef Vec vec_ZZ_pE; void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b); inline void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b) { mul(x, b, a); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b); inline void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b) { mul(x, b, a); } void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b); inline void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b) { mul(x, b, a); } void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a); void clear(vec_ZZ_pE& x); void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset); long IsZero(const vec_ZZ_pE& a); void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n); inline vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n) { vec_ZZ_pE x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_ZZ_pE, x); } vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a); inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } inline vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b) { vec_ZZ_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_ZZ_pE, x); } ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // assignment operator notation: inline vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a) { add(x, x, a); return x; } inline vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a) { sub(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a) { mul(x, x, a); return x; } inline vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a) { mul(x, x, a); return x; } void random(vec_ZZ_pE& x, long n); inline vec_ZZ_pE random_vec_ZZ_pE(long n) { vec_ZZ_pE x; random(x, n); NTL_OPT_RETURN(vec_ZZ_pE, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_double.h0000644417616742025610000000022414064716022020513 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_double__H #define NTL_vec_double__H #include NTL_OPEN_NNS typedef Vec vec_double; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_long.h0000644417616742025610000000021414064716022020177 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_long__H #define NTL_vec_long__H #include NTL_OPEN_NNS typedef Vec vec_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_lzz_p.h0000644417616742025610000000470314064716022020405 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_zz_p__H #define NTL_vec_zz_p__H #include #include NTL_OPEN_NNS typedef Vec vec_zz_p; // legacy conversion notation inline vec_zz_p to_vec_zz_p(const vec_ZZ& a) { vec_zz_p x; conv(x, a); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_ZZ to_vec_ZZ(const vec_zz_p& a) { vec_ZZ x; conv(x, a); NTL_OPT_RETURN(vec_ZZ, x); } long CRT(vec_ZZ& g, ZZ& a, const vec_zz_p& G); void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void clear(vec_zz_p& x); void negate(vec_zz_p& x, const vec_zz_p& a); void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b); void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset); void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b); inline void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b) { mul(x, b, a); } void mul(vec_zz_p& x, const vec_zz_p& a, long b); inline void mul(vec_zz_p& x, long a, const vec_zz_p& b) { mul(x, b, a); } long IsZero(const vec_zz_p& a); void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n); inline vec_zz_p VectorCopy(const vec_zz_p& a, long n) { vec_zz_p x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_zz_p, x); } vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a); zz_p operator*(const vec_zz_p& a, const vec_zz_p& b); inline vec_zz_p operator*(const vec_zz_p& a, zz_p b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(const vec_zz_p& a, long b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(zz_p a, const vec_zz_p& b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } inline vec_zz_p operator*(long a, const vec_zz_p& b) { vec_zz_p x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_p, x); } // assignment operator notation: inline vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a) { add(x, x, a); return x; } inline vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a) { sub(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, zz_p a) { mul(x, x, a); return x; } inline vec_zz_p& operator*=(vec_zz_p& x, long a) { mul(x, x, a); return x; } void random(vec_zz_p& x, long n); inline vec_zz_p random_vec_zz_p(long n) { vec_zz_p x; random(x, n); NTL_OPT_RETURN(vec_zz_p, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_lzz_pE.h0000644417616742025610000000535414064716022020515 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_zz_pE__H #define NTL_vec_zz_pE__H #include NTL_OPEN_NNS typedef Vec vec_zz_pE; void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b); inline void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b) { mul(x, b, a); } void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b); inline void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b) { mul(x, b, a); } void mul(vec_zz_pE& x, const vec_zz_pE& a, long b); inline void mul(vec_zz_pE& x, long a, const vec_zz_pE& b) { mul(x, b, a); } void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void negate(vec_zz_pE& x, const vec_zz_pE& a); void clear(vec_zz_pE& x); void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset); long IsZero(const vec_zz_pE& a); void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n); inline vec_zz_pE VectorCopy(const vec_zz_pE& a, long n) { vec_zz_pE x; VectorCopy(x, a, n); NTL_OPT_RETURN(vec_zz_pE, x); } vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a); inline vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const vec_zz_pE& a, long b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } inline vec_zz_pE operator*(long a, const vec_zz_pE& b) { vec_zz_pE x; mul(x, a, b); NTL_OPT_RETURN(vec_zz_pE, x); } zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b); // assignment operator notation: inline vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a) { add(x, x, a); return x; } inline vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a) { sub(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a) { mul(x, x, a); return x; } inline vec_zz_pE& operator*=(vec_zz_pE& x, long a) { mul(x, x, a); return x; } void random(vec_zz_pE& x, long n); inline vec_zz_pE random_vec_zz_pE(long n) { vec_zz_pE x; random(x, n); NTL_OPT_RETURN(vec_zz_pE, x); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_quad_float.h0000644417616742025610000000030014064716022021353 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_quad_float__H #define NTL_vec_quad_float__H #include #include NTL_OPEN_NNS typedef Vec vec_quad_float; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_GF2.h0000644417616742025610000000026414064716022020460 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_GF2__H #define NTL_vec_vec_GF2__H #include #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_GF2; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_GF2E.h0000644417616742025610000000024114064716022020560 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_GF2E__H #define NTL_vec_vec_GF2E__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_GF2E; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_RR.h0000644417616742025610000000022714064716022020424 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_RR__H #define NTL_vec_vec_RR__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_RR; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_ZZ.h0000644417616742025610000000022714064716022020444 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_ZZ__H #define NTL_vec_vec_ZZ__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_ZZ_p.h0000644417616742025610000000024114064716022020757 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_ZZ_p__H #define NTL_vec_vec_ZZ_p__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ_p; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_ZZ_pE.h0000644417616742025610000000024614064716022021071 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_ZZ_pE__H #define NTL_vec_vec_ZZ_pE__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ZZ_pE; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_long.h0000644417616742025610000000024214064716022021035 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_long__H #define NTL_vec_vec_long__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_long; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_lzz_p.h0000644417616742025610000000024214064716022021234 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_zz_p__H #define NTL_vec_vec_zz_p__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_zz_p; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_lzz_pE.h0000644417616742025610000000024714064716022021346 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_zz_pE__H #define NTL_vec_vec_zz_pE__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_zz_pE; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_xdouble.h0000644417616742025610000000026214064716022020705 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_xdouble__H #define NTL_vec_xdouble__H #include #include NTL_OPEN_NNS typedef Vec vec_xdouble; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/xdouble.h0000644417616742025610000002030614064716022020051 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_xdouble__H #define NTL_xdouble__H #include NTL_OPEN_NNS // NTL_XD_HBOUND = 2^{max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4} #if (NTL_DOUBLE_PRECISION > NTL_BITS_PER_LONG) #define NTL_XD_HBOUND (NTL_FDOUBLE_PRECISION*32.0) #define NTL_XD_HBOUND_LOG (NTL_DOUBLE_PRECISION+4) #else #define NTL_XD_HBOUND (double(1L << (NTL_BITS_PER_LONG - 2))*64.0) #define NTL_XD_HBOUND_LOG (NTL_BITS_PER_LONG+4) #endif #define NTL_XD_HBOUND_INV (double(1)/NTL_XD_HBOUND) #define NTL_XD_BOUND (NTL_XD_HBOUND*NTL_XD_HBOUND) #define NTL_XD_BOUND_INV (double(1)/NTL_XD_BOUND) class xdouble { public: double x; long e; xdouble() : x(0), e(0) { } explicit xdouble(double a) : x(0), e(0) { *this = a; } inline xdouble& operator=(double a); void normalize(); static NTL_CHEAP_THREAD_LOCAL long oprec; static void SetOutputPrecision(long p); static long OutputPrecision() { return oprec; } double mantissa() const { return x; } long exponent() const { return e; } xdouble(double xx, long ee) : x(xx), e(ee) { } // internal use only }; NTL_DECLARE_RELOCATABLE((xdouble*)) inline xdouble to_xdouble(int a) { return xdouble(a, 0); } inline xdouble to_xdouble(long a) { return xdouble(a, 0); } inline xdouble to_xdouble(unsigned int a) { return xdouble(a, 0); } inline xdouble to_xdouble(unsigned long a) { return xdouble(a, 0); } xdouble to_xdouble(double a); inline xdouble to_xdouble(float a) { return to_xdouble(double(a)); } inline xdouble to_xdouble(const char *a) { xdouble res; conv(res, a); return res; } inline xdouble& xdouble::operator=(double a) { *this = to_xdouble(a); return *this; } xdouble operator+(const xdouble& a, const xdouble& b); inline xdouble operator+(const xdouble& a, double b) { return a + to_xdouble(b); } inline xdouble operator+(double a, const xdouble& b) { return to_xdouble(a) + b; } xdouble operator-(const xdouble& a, const xdouble& b); inline xdouble operator-(const xdouble& a, double b) { return a - to_xdouble(b); } inline xdouble operator-(double a, const xdouble& b) { return to_xdouble(a) - b; } xdouble operator*(const xdouble& a, const xdouble& b); inline xdouble operator*(const xdouble& a, double b) { return a * to_xdouble(b); } inline xdouble operator*(double a, const xdouble& b) { return to_xdouble(a) * b; } xdouble operator/(const xdouble& a, const xdouble& b); inline xdouble operator/(const xdouble& a, double b) { return a / to_xdouble(b); } inline xdouble operator/(double a, const xdouble& b) { return to_xdouble(a) / b; } xdouble operator-(const xdouble& a); inline xdouble& operator+=(xdouble& a, const xdouble& b) { a = a + b; return a; } inline xdouble& operator+=(xdouble& a, double b) { a = a + b; return a; } inline xdouble& operator-=(xdouble& a, const xdouble& b) { a = a - b; return a; } inline xdouble& operator-=(xdouble& a, double b) { a = a - b; return a; } inline xdouble& operator*=(xdouble& a, const xdouble& b) { a = a * b; return a; } inline xdouble& operator*=(xdouble& a, double b) { a = a * b; return a; } inline xdouble& operator/=(xdouble& a, const xdouble& b) { a = a / b; return a; } inline xdouble& operator/=(xdouble& a, double b) { a = a / b; return a; } inline xdouble& operator++(xdouble& a) { a = a + to_xdouble(1); return a; } inline xdouble& operator--(xdouble& a) { a = a - to_xdouble(1); return a; } inline void operator++(xdouble& a, int) { a = a + to_xdouble(1); } inline void operator--(xdouble& a, int) { a = a - to_xdouble(1); } long compare(const xdouble& a, const xdouble& b); inline long compare(const xdouble& a, double b) { return compare(a, to_xdouble(b)); } inline long compare(double a, const xdouble& b) { return compare(to_xdouble(a), b); } long sign(const xdouble& a); inline long operator==(const xdouble& a, const xdouble& b) { return compare(a, b) == 0; } inline long operator!=(const xdouble& a, const xdouble& b) { return compare(a, b) != 0; } inline long operator<=(const xdouble& a, const xdouble& b) { return compare(a, b) <= 0; } inline long operator>=(const xdouble& a, const xdouble& b) { return compare(a, b) >= 0; } inline long operator <(const xdouble& a, const xdouble& b) { return compare(a, b) < 0; } inline long operator >(const xdouble& a, const xdouble& b) { return compare(a, b) > 0; } inline long operator==(const xdouble& a, double b) { return compare(a, b) == 0; } inline long operator!=(const xdouble& a, double b) { return compare(a, b) != 0; } inline long operator<=(const xdouble& a, double b) { return compare(a, b) <= 0; } inline long operator>=(const xdouble& a, double b) { return compare(a, b) >= 0; } inline long operator <(const xdouble& a, double b) { return compare(a, b) < 0; } inline long operator >(const xdouble& a, double b) { return compare(a, b) > 0; } inline long operator==(double a, const xdouble& b) { return compare(a, b) == 0; } inline long operator!=(double a, const xdouble& b) { return compare(a, b) != 0; } inline long operator<=(double a, const xdouble& b) { return compare(a, b) <= 0; } inline long operator>=(double a, const xdouble& b) { return compare(a, b) >= 0; } inline long operator <(double a, const xdouble& b) { return compare(a, b) < 0; } inline long operator >(double a, const xdouble& b) { return compare(a, b) > 0; } void conv(ZZ& x, const xdouble& a); // x = floor(a); inline ZZ to_ZZ(const xdouble& a) { ZZ x; conv(x, a); NTL_OPT_RETURN(ZZ, x); } xdouble to_xdouble(const ZZ& a); inline void conv(xdouble& z, const ZZ& a) { z = to_xdouble(a); } void conv(double& x, const xdouble& a); inline double to_double(const xdouble& a) { double z; conv(z, a); return z; } inline void conv(float& x, const xdouble& a) { double t; conv(t, a); x = float(t); } inline float to_float(const xdouble& a) { float z; conv(z, a); return z; } inline void conv(long& x, const xdouble& a) { double z; conv(z, a); x = long(NTL_SNS floor(z)); } inline long to_long(const xdouble& a) { long z; conv(z, a); return z; } inline void conv(int& x, const xdouble& a) { double z; conv(z, a); x = int(NTL_SNS floor(z)); } inline int to_int(const xdouble& a) { int z; conv(z, a); return z; } inline void conv(xdouble& x, const xdouble& a) { x = a; } inline xdouble to_xdouble(const xdouble& a) { return a; } inline void conv(xdouble& x, int a) { x = to_xdouble(a); } inline void conv(xdouble& x, long a) { x = to_xdouble(a); } inline void conv(xdouble& x, unsigned int a) { x = to_xdouble(a); } inline void conv(xdouble& x, unsigned long a) { x = to_xdouble(a); } inline void conv(xdouble& x, float a) { x = to_xdouble(a); } inline void conv(xdouble& x, double a) { x = to_xdouble(a); } /* additional legacy conversions for v6 conversion regime */ inline void conv(unsigned int& x, const xdouble& a) { long z; conv(z, a); conv(x, z); } inline void conv(unsigned long& x, const xdouble& a) { long z; conv(z, a); conv(x, z); } /* ------------------------------------- */ NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const xdouble& a); NTL_SNS istream& operator>>(NTL_SNS istream& s, xdouble& x); xdouble trunc(const xdouble& a); xdouble floor(const xdouble& a); xdouble ceil(const xdouble& a); xdouble fabs(const xdouble& a); xdouble sqrt(const xdouble& a); void power(xdouble& z, const xdouble& a, const ZZ& e); inline xdouble power(const xdouble& a, const ZZ& e) { xdouble z; power(z, a, e); return z; } void power(xdouble& z, const xdouble& a, long e); inline xdouble power(const xdouble& a, long e) { xdouble z; power(z, a, e); return z; } void power2(xdouble& z, long e); inline xdouble power2_xdouble(long e) { xdouble z; power2(z, e); return z; } void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); inline xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c) { xdouble z; MulAdd(z, a, b, c); return z; } void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); inline xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c) { xdouble z; MulSub(z, a, b, c); return z; } double log(const xdouble& a); xdouble xexp(double x); inline xdouble exp(const xdouble& x) { return xexp(to_double(x)); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/config.h0000644417616742025610000002555114064716022017663 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_config__H #define NTL_config__H /************************************************************************* NTL Configuration File ---------------------- This file is automatically generated by the configure script. You can also edit this file by hand, but that is not generally recommended. To set a flag, just replace the pre-processor directive 'if 0' by 'if 1' for that flag, which causes the appropriate macro to be defined. Of course, to unset a flag, just replace the 'if 1' by an 'if 0'. *************************************************************************/ /************************************************************************* * * Basic Configuration Options * *************************************************************************/ /* None of these flags are set by the configuration wizard; * they must be set by hand, before installation begins. */ #if 0 #define NTL_LEGACY_NO_NAMESPACE /* * By default, NTL components are declared inside the namespace NTL. * Set this flag if you want to instead have these components * declared in the global namespace. This is for backward * compatibility only -- not recommended. * */ #endif #if 0 #define NTL_LEGACY_INPUT_ERROR /* * Also for backward compatibility. Set if you want input * operations to abort on error, instead of just setting the * "fail bit" of the input stream. * */ #endif #if 1 #define NTL_TLS_HACK /* Set if you want to compile NTL with "TLS hack" * */ #endif #if 1 #define NTL_THREADS /* Set if you want to compile NTL as a thread-safe library. * */ #endif #if 0 #define NTL_EXCEPTIONS /* Set if you want to compile NTL with exceptions enabled * */ #endif #if 1 #define NTL_THREAD_BOOST /* Set if you want to compile NTL to exploit threads internally. * */ #endif #if 1 #define NTL_GMP_LIP /* * Use this flag if you want to use GMP as the long integer package. * This can result in significantly faster code on some platforms. * It requires that the GMP package (version >= 3.1) has already been * installed. You will also have to set the variables GMP_OPT_INCDIR, * GMP_OPT_LIBDIR, GMP_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GMP_LIP=on * to that script. * * Beware that setting this flag can break some very old NTL codes. * * You may also have to edit the makefile to modify the variables * GMP_OPT_INCDIR, GMP_OPT_LIBDIR, and GMP_OPT_LIB. */ #endif #if 0 #define NTL_GF2X_LIB /* * Use this flag if you want to use the gf2x library for * faster GF2X arithmetic. * This can result in significantly faster code, especially * when working with polynomials of huge degree. * You will also have to set the variables GF2X_OPT_INCDIR, * GF2X_OPT_LIBDIR, GF2X_OPT_LIB in the makefile (these are set automatically * by the confiuration script when you pass the flag NTL_GF2X_LIB=on * to that script. * * You may also have to edit the makefile to modify the variables * GF2X_OPT_INCDIR, GF2X_OPT_LIBDIR, and GF2X_OPT_LIB. */ #endif #if 1 #define NTL_STD_CXX11 /* * Set this flag if you want to enable C++11 features within NTL. */ #endif #if 0 #define NTL_STD_CXX14 /* * Set this flag if you want to enable C++14 features within NTL. */ #endif #if 1 #define NTL_DISABLE_MOVE_ASSIGN /* * Set this flag if you want to disable move assignment * operators for vectors (and, by extension, polynomials) * and matrices. */ #endif #if 0 #define NTL_DISABLE_MOVE /* * This flag disables all move constructors and assignments. */ #endif #if 0 #define NTL_UNSIGNED_LONG_LONG_TYPE unsigned long long /* * NTL_UNSIGNED_LONG_LONG_TYPE will be used * to declare 'double word' unsigned integer types. * If left undefined, some "ifdef magic" will attempt * to find the best choice for your platform, depending * on the compiler and wordsize. On 32-bit machines, * this is usually 'unsigned long long'. * */ #endif #if 0 #define NTL_CLEAN_INT /* * This will disallow the use of some non-standard integer arithmetic * that may improve performance somewhat. * */ #endif #if 1 #define NTL_CLEAN_PTR /* * This will disallow the use of some non-standard pointer arithmetic * that may improve performance somewhat. * */ #endif #if 1 #define NTL_SAFE_VECTORS /* * This will compile NTL in "safe vector" mode, only assuming * the relocatability property for trivial types and types * explicitly declared relocatable. See vector.txt for more details. */ #endif #if 0 #define NTL_ENABLE_AVX_FFT /* * This will compile NTL in a way that enables an AVX implemention * of the small-prime FFT. */ #endif #if 0 #define NTL_AVOID_AVX512 /* * This will compile NTL in a way that avoids 512-bit operations, * even if AVX512 is available. */ #endif #if 0 #define NTL_RANGE_CHECK /* * This will generate vector subscript range-check code. * Useful for debugging, but it slows things down of course. * */ #endif #if 1 #define NTL_NO_INIT_TRANS /* * Without this flag, NTL uses a special code sequence to avoid * copying large objects in return statements. However, if your * compiler optimizes away the return of a *named* local object, * this is not necessary, and setting this flag will result * in *slightly* more compact and efficient code. Although * the emeriging C++ standard allows compilers to perform * this optimization, I know of none that currently do. * Most will avoid copying *temporary* objects in return statements, * and NTL's default code sequence exploits this fact. * */ #endif #if 0 #define NTL_X86_FIX /* * Forces the "x86 floating point fix", overriding the default behavior. * By default, NTL will apply the "fix" if it looks like it is * necessary, and if knows how to fix it. * The problem addressed here is that x86 processors sometimes * run in a mode where FP registers have more precision than doubles. * This will cause code in quad_float.cpp some trouble. * NTL can normally correctly detect the problem, and fix it, * so you shouldn't need to worry about this or the next flag. * */ #elif 0 #define NTL_NO_X86_FIX /* * Forces no "x86 floating point fix", overriding the default behavior. */ #endif #if 0 #define NTL_LEGACY_SP_MULMOD /* Forces legacy single-precision MulMod implementation. */ #endif #if 0 #define NTL_DISABLE_LONGDOUBLE /* Explicitly disables us of long double arithmetic */ #endif #if 0 #define NTL_DISABLE_LONGLONG /* Explicitly disables us of long long arithmetic */ #endif #if 0 #define NTL_DISABLE_LL_ASM /* Explicitly disables us of inline assembly as a replacement * for long lobg arithmetic. */ #endif #if 0 #define NTL_MAXIMIZE_SP_NBITS /* Allows for 62-bit single-precision moduli on 64-bit platforms. * By default, such moduli are restricted to 60 bits, which * usually gives slightly better performance across a range of * of parameters. */ #endif /************************************************************************* * * Performance Options * *************************************************************************/ /* There are three strategies to implmement single-precision * modular multiplication with preconditioning (see the MulModPrecon * function in the ZZ module): the default and NTL_SPMM_ULL. * This plays a crucial role in the "small prime FFT" used to * implement polynomial arithmetic, and in other CRT-based methods * (such as linear algebra over ZZ), as well as polynomial and matrix * arithmetic over zz_p. */ #if 1 #define NTL_SPMM_ULL /* This also causes an "all integer" * implementation of MulModPrecon to be used. * It us usually a faster implementation, * but it is not enturely portable. * It relies on double-word unsigned multiplication * (see NTL_UNSIGNED_LONG_LONG_TYPE above). * */ #endif /* * The following two flags provide additional control for how the * FFT modulo single-precision primes is implemented. */ #if 1 #define NTL_FFT_BIGTAB /* * Precomputed tables are used to store all the roots of unity * used in FFT computations. * */ #endif #if 1 #define NTL_FFT_LAZYMUL /* * When set, a "lazy multiplication" strategy due to David Harvey: * see his paper "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". * */ #endif #if 0 #define NTL_AVOID_BRANCHING /* * With this option, branches are replaced at several * key points with equivalent code using shifts and masks. * It may speed things up on machines with * deep pipelines and high branch penalities. * This flag mainly affects the implementation of the * single-precision modular arithmetic routines. * */ #endif #if 1 #define NTL_TBL_REM /* * * With this flag, some divisions are avoided in the * ZZ_pX multiplication routines. * */ #endif #if 1 #define NTL_CRT_ALTCODE /* * Employs an alternative CRT strategy. * Only relevant with GMP. * Seems to be marginally faster on some x86_64 platforms. * */ #endif #if 0 #define NTL_CRT_ALTCODE_SMALL /* * Employs an alternative CRT strategy for small moduli. * Only relevant with GMP. * Seems to be marginally faster on some x86_64 platforms. * */ #endif #if 0 #define NTL_GF2X_ALTCODE /* * With this option, the default strategy for implmenting low-level * GF2X multiplication is replaced with an alternative strategy. * This alternative strategy seems to work better on RISC machines * with deep pipelines and high branch penalties (like a powerpc), * but does no better (or even worse) on x86s. * */ #elif 1 #define NTL_GF2X_ALTCODE1 /* * Yest another alternative strategy for implementing GF2X * multiplication. * */ #endif #if 0 #define NTL_GF2X_NOINLINE /* * By default, the low-level GF2X multiplication routine in inlined. * This can potentially lead to some trouble on some platforms, * and you can override the default by setting this flag. * */ #endif #if 0 #define NTL_RANDOM_AES256CTR /* * By default, the random-number generator is based on ChaCha20. * From a performance perspective, this choice may not be optimal * for platforms featuring AES hardware support. * By setting this flag you can override the default and use an * AES-256-CTR based random-number generator. * */ #endif /* sanity checks */ #if (defined(NTL_THREAD_BOOST) && !defined(NTL_THREADS)) #error "NTL_THREAD_BOOST defined but not NTL_THREADS" #endif #if (defined(NTL_THREADS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_THREADS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif #if (defined(NTL_EXCEPTIONS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_EXCEPTIONS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif #if (defined(NTL_SAFE_VECTORS) && !(defined(NTL_STD_CXX11) || defined(NTL_STD_CXX14))) #error "NTL_SAFE_VECTORS defined but not NTL_STD_CXX11 or NTL_STD_CXX14" #endif #endif ntl-11.5.1/include/NTL/version.h0000644417616742025610000000026514064716022020076 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_version__H #define NTL_version__H #define NTL_VERSION "11.5.1" #define NTL_MAJOR_VERSION (11) #define NTL_MINOR_VERSION (5) #define NTL_REVISION (1) #endif ntl-11.5.1/include/NTL/new.h0000644417616742025610000000014614064716022017200 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_new__H #define NTL_new__H #include #define NTL_NEW_OP new (std::nothrow) #endif ntl-11.5.1/include/NTL/vec_ulong.h0000644417616742025610000000023014064716022020362 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_ulong__H #define NTL_vec_ulong__H #include NTL_OPEN_NNS typedef Vec vec_ulong; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/vec_vec_ulong.h0000644417616742025610000000025714064716022021230 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_vec_vec_ulong__H #define NTL_vec_vec_ulong__H #include NTL_OPEN_NNS typedef Vec< Vec > vec_vec_ulong; NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/SmartPtr.h0000644417616742025610000013421114064716022020164 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_SmartPtr__H #define NTL_SmartPtr__H #include #include // NOTE: includes , which provides std::forward NTL_OPEN_NNS /**************************************************************************** SmartPtr: a smart pointer class. Synopsis: provides a reference counted smart pointer, similar to shared_ptr in the standard library. It is provided here to minimize reliance on the standard library, especially for older C++ compilers, which may not provide shared_ptr, or it may be in TR1, which gets messy. Examples: SmartPtr p1; // initialize to null SmartPtr p1(0); SmartPtr p1 = 0; SmartPtr p2(p1); // copy constructor T *rp; SmartPtr p2(rp); // construct using raw pointer (explicit): better // to use MakeSmart below p1 = MakeSmart(...); // build new T object by invoking constructor // T(...) with pseudo-variadic templates. // This is safer and more efficient that // using the raw-pointer constructor p1 = p2; // assignment p1 = 0; // assign null if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for not null ... if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) *p1 // dereferencing p1->... p1.get(); // return the underlying raw pointer...dangerous! p1.swap(p2); // fast swap swap(p1, p2); Automatic Conversions: If S is another class, SmartPtr converts to SmartPtr if S* converts to T* (for example, if S is a subclass of T). Similarly, SmartPtr and SmartPtr may be compared if S* and T* may be compared. MakeSmart: One can write SmartPtr p = MakeSmart(x1, ..., xn), and this will create a smart pointer to an object constructed as T(x1, ..., xn). Besides notational convenience, it also reduces the number of memory allocations from 2 to 1, as the data and control block can be allocated in one chunck of memory. This is implemented without reliance on C++11 features, which means that there are limitations. First, the number n of arguments is limited to 9. And second, all arguments are pass by const reference. However, you can work around this by using the helper function Fwd. For example, if T has a 2-argument constructor where the second must be a non-const reference of some type, and x2 is a variable of that type, you can write MakeSmart(x1, Fwd(x2)), to forward that reference through all the template nonsense in a typesafe manner. MakeRaw: One can also write T *p = MakeRaw(x1, ..., xn) to create a raw pointer. This is the same as writing T *p = new T(x1, ..., xn), except that if the construction fails, NTL's error routine will be called (as opposed to an exception being thrown). The same restrictions and limitations that apply to MakeSmart appy to MakeRaw. MakeRawArray: Another utility routine: one can write T *p = MakeRawArray(n) to make a plain array of n T's. NTL's error routine will be called if the allocation fails. Dynamic casting: I've also supplied a dynamic cast operation for smart pointers. SmartPtr d = MakeSmart(); // d points to Derived SmartPtr b = d; // implicit upcast: OK SmartPtr d1 = DynamicCast(b); // downcast to a Derived object -- returns null for a bad cast Implementation notes: If NTL is compiled with the NTL_THREADS option, then the reference counting should be thread safe. The SmartPtrControl class heirarchy is used to make sure the right destructor is called when the ref count goes to zero. This can be an issue for forward declared classes and for subclasses. For example, if T is forward declared in a context where the ref count goes to zero, or if the object's actual type is a subclass of T and T's destructor was not declared virtual. The null tests p, !p, p == 0, are all affected via an implicit conversion from SmartPtr to a funny pointer type (a pointer to a member function, which avoids other, unwanted implicit conversions: this is the so-called "safe bool idiom"); There is also an assigmment from a funny pointer type to a SmartPtr, which asslows assigment of 0 to a SmartPtr. In C++11 both of the above effects could perhaps be achieved more directly. The new "explict bool" operator can replace the "safe bool idiom", and I would think that the new null pointer type could be used to get the assignment of 0 to work. NOTES: See http://www.artima.com/cppsource/safebool.html for more on the "safe bool idiom". *****************************************************************************/ // Helper class for somewhat finer-grained control of deleter. // Useful in the PIMPL pattern. struct DefaultDeleterPolicy { template static void deleter(T *p) { delete p; } }; // A tagging class, for better readability template struct ChoosePolicy { }; // usage: SmartPtr p(r, ChoosePolicy()); class SmartPtrControl { public: AtomicRefCount cnt; SmartPtrControl() { } virtual ~SmartPtrControl() { } private: void operator=(const SmartPtrControl&); // =delete SmartPtrControl(const SmartPtrControl&); // =delete }; template class SmartPtrControlDerived : public SmartPtrControl { public: T* p; SmartPtrControlDerived(T* _p) : p(_p) { } ~SmartPtrControlDerived() { P::deleter(p); } }; struct SmartPtrLoopHole { }; template class SmartPtr { private: T *dp; SmartPtrControl *cp; void AddRef() const { if (cp) cp->cnt.inc(); } void RemoveRef() const { if (cp && cp->cnt.dec()) { delete cp; } } class Dummy { }; typedef void (SmartPtr::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (SmartPtr::*fake_null_type1)(Dummy1) const; public: long get_count() const { return cp ? cp->cnt.get_count() : 0; } // mainly for debugging template explicit SmartPtr(Y* p) : dp(p), cp(0) { if (p) { cp = NTL_NEW_OP SmartPtrControlDerived(p); if (!cp) { delete p; // this could theoretically throw an exception MemoryError(); } AddRef(); } } template SmartPtr(Y* p, ChoosePolicy

) : dp(p), cp(0) { if (p) { cp = NTL_NEW_OP SmartPtrControlDerived(p); if (!cp) { delete p; // this could theoretically throw an exception MemoryError(); } AddRef(); } } SmartPtr() : dp(0), cp(0) { } SmartPtr(fake_null_type1) : dp(0), cp(0) { } SmartPtr(SmartPtrLoopHole, T* _dp, SmartPtrControl *_cp) : dp(_dp), cp(_cp) { AddRef(); } ~SmartPtr() { RemoveRef(); } SmartPtr(const SmartPtr& other) : dp(other.dp), cp(other.cp) { AddRef(); } SmartPtr& operator=(const SmartPtr& other) { SmartPtr tmp(other); tmp.swap(*this); return *this; } template friend class SmartPtr; template SmartPtr(const SmartPtr& other) : dp(other.dp), cp(other.cp) { AddRef(); } template SmartPtr& operator=(const SmartPtr& other) { SmartPtr tmp(other); tmp.swap(*this); return *this; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) SmartPtr(SmartPtr&& other) noexcept : dp(other.dp), cp(other.cp) { other.dp = 0; other.cp = 0; } SmartPtr& operator=(SmartPtr&& other) noexcept { SmartPtr tmp(std::move(other)); tmp.swap(*this); return *this; } template SmartPtr(SmartPtr&& other) noexcept : dp(other.dp), cp(other.cp) { other.dp = 0; other.cp = 0; } template SmartPtr& operator=(SmartPtr&& other) noexcept { SmartPtr tmp(std::move(other)); tmp.swap(*this); return *this; } #endif T& operator*() const { return *dp; } T* operator->() const { return dp; } T* get() const { return dp; } void swap(SmartPtr& other) { _ntl_swap(dp, other.dp); _ntl_swap(cp, other.cp); } operator fake_null_type() const { return dp ? &SmartPtr::fake_null_function : 0; } template SmartPtr DynamicCast() const { if (!dp) return SmartPtr(); else { Y* dp1 = dynamic_cast(dp); if (!dp1) return SmartPtr(); return SmartPtr(SmartPtrLoopHole(), dp1, cp); } } }; template NTL_DECLARE_RELOCATABLE((SmartPtr*)) // free swap function template void swap(SmartPtr& p, SmartPtr& q) { p.swap(q); } // free dynamic cast function template SmartPtr DynamicCast(const SmartPtr& p) { return p.template DynamicCast(); } // Equality testing template bool operator==(const SmartPtr& a, const SmartPtr& b) { return a.get() == b.get(); } template bool operator!=(const SmartPtr& a, const SmartPtr& b) { return a.get() != b.get(); } /********************************************************************************* Experimantal: CloneablePtr ...essentially same interface as SmartPtr, but allows cloning of complete objects. The differences: * must construct using MakeCloneable * a clone method is provided * implicit conversion from CloneablePtr to SmartPtr is allowed Example: CloneablePtr d = MakeCloneable(); // d points to Derived CloneablePtr b = d; // implicit upcast: OK CloneablePtr b1 = b.clone(); // clone of b, which is really a Derived object CloneablePtr d1 = DynamicCast(b1); // downcast to a Derived object -- returns null for a bad cast SmartPtr b2 = d1; Implementation: In the clone method, the object is constructed using the copy constructor for the type T, where T is the compile-time type with which the first smart pointer to this object was was created, even if the pointer has been subsequently upcasted to a base type S. Such objects must have been initially created using the MakeCloneable function. It turns out, this is hard to do in a completely standards-compliant way, because of the type erasure going on. The only way I could figure out how to do it in a standards-compliant way was by using exceptions: the control block throws a T* and the smart pointer doing the clone catches an S*. However, this turned out to be dreadfully slow, and even this does not completely solve the problem, because there could be ambiguities in this type of upcasting that miay arise with multiple inheritance. So I settled on the current method, which does some low-level pointer arithmetic. Even with fancy things like multiple and virtual inheritance, it should work, under the assumption that if two objects have the same (runtime) type, then their memory layout is the same. I don't think anything like that is guaranteed by the standard, but this seems reasonable, and it seems to work. Like I said, it is experimental, and I would appreciate feedback from C++ gurus. Note that NTL does not use this feature, but I do have applications where this is convenient. **********************************************************************************/ class CloneablePtrControl : public SmartPtrControl { public: virtual CloneablePtrControl *clone() const = 0; virtual void *get() = 0; }; template class CloneablePtrControlDerived : public CloneablePtrControl { public: T d; CloneablePtrControlDerived(const T& x) : d(x) { } CloneablePtrControl *clone() const { CloneablePtrControl *q = NTL_NEW_OP CloneablePtrControlDerived(d); if (!q) MemoryError(); return q; } void *get() { return &d; } }; struct CloneablePtrLoopHole { }; template class CloneablePtr { private: T *dp; CloneablePtrControl *cp; void AddRef() const { if (cp) cp->cnt.inc(); } void RemoveRef() const { if (cp && cp->cnt.dec()) { delete cp; } } class Dummy { }; typedef void (CloneablePtr::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (CloneablePtr::*fake_null_type1)(Dummy1) const; public: long get_count() const { return cp ? cp->cnt.get_count() : 0; } // mainly for debugging CloneablePtr() : dp(0), cp(0) { } CloneablePtr(fake_null_type1) : dp(0), cp(0) { } CloneablePtr(CloneablePtrLoopHole, T* _dp, CloneablePtrControl *_cp) : dp(_dp), cp(_cp) { AddRef(); } ~CloneablePtr() { RemoveRef(); } CloneablePtr(const CloneablePtr& other) : dp(other.dp), cp(other.cp) { AddRef(); } CloneablePtr& operator=(const CloneablePtr& other) { CloneablePtr tmp(other); tmp.swap(*this); return *this; } template friend class CloneablePtr; template CloneablePtr(const CloneablePtr& other) : dp(other.dp), cp(other.cp) { AddRef(); } template CloneablePtr& operator=(const CloneablePtr& other) { CloneablePtr tmp(other); tmp.swap(*this); return *this; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) CloneablePtr(CloneablePtr&& other) noexcept : dp(other.dp), cp(other.cp) { other.dp = 0; other.cp = 0; } CloneablePtr& operator=(CloneablePtr&& other) noexcept { CloneablePtr tmp(std::move(other)); tmp.swap(*this); return *this; } template CloneablePtr(CloneablePtr&& other) noexcept : dp(other.dp), cp(other.cp) { other.dp = 0; other.cp = 0; } template CloneablePtr& operator=(CloneablePtr&& other) noexcept { CloneablePtr tmp(std::move(other)); tmp.swap(*this); return *this; } #endif T& operator*() const { return *dp; } T* operator->() const { return dp; } T* get() const { return dp; } void swap(CloneablePtr& other) { _ntl_swap(dp, other.dp); _ntl_swap(cp, other.cp); } operator fake_null_type() const { return dp ? &CloneablePtr::fake_null_function : 0; } template CloneablePtr DynamicCast() const { if (!dp) return CloneablePtr(); else { Y* dp1 = dynamic_cast(dp); if (!dp1) return CloneablePtr(); return CloneablePtr(CloneablePtrLoopHole(), dp1, cp); } } CloneablePtr clone() const { if (!dp) return CloneablePtr(); else { CloneablePtrControl *cp1 = cp->clone(); char *complete = (char *) cp->get(); char *complete1 = (char *) cp1->get(); T *dp1 = (T *) (complete1 + (((char *)dp) - complete)); return CloneablePtr(CloneablePtrLoopHole(), dp1, cp1); } } template operator SmartPtr() { return SmartPtr(SmartPtrLoopHole(), dp, cp); } }; template NTL_DECLARE_RELOCATABLE((CloneablePtr*)) // free swap function template void swap(CloneablePtr& p, CloneablePtr& q) { p.swap(q); } // free dynamic cast function template CloneablePtr DynamicCast(const CloneablePtr& p) { return p.template DynamicCast(); } // Equality testing template bool operator==(const CloneablePtr& a, const CloneablePtr& b) { return a.get() == b.get(); } template bool operator!=(const CloneablePtr& a, const CloneablePtr& b) { return a.get() != b.get(); } // ****************************************************** // Implementation of MakeSmart and friends #if (NTL_CXX_STANDARD >= 2011) // Declared for backward compatibility with pre-C++11 NTL clients template T& Fwd(T& x) { return x; } template const T& Fwd(const T& x) { return x; } template class MakeSmartAux : public SmartPtrControl { public: T d; template MakeSmartAux(Args&&... args) : d(std::forward(args)...) { } }; template SmartPtr MakeSmart(Args&&... args) { MakeSmartAux *cp = NTL_NEW_OP MakeSmartAux( std::forward(args)... ); if (!cp) MemoryError(); return SmartPtr(SmartPtrLoopHole(), &cp->d, cp); } template class MakeCloneableAux : public CloneablePtrControl { public: T d; template MakeCloneableAux(Args&&... args) : d(std::forward(args)...) { } CloneablePtrControl *clone() const \ { CloneablePtrControl *q = NTL_NEW_OP CloneablePtrControlDerived(d); if (!q) MemoryError(); return q; } void *get() { return &d; } }; #ifdef NTL_TEST_EXCEPTIONS template T* MakeRaw(Args&&... args) { T *p = 0; if (--exception_counter != 0) p = NTL_NEW_OP T(std::forward(args)...); if (!p) MemoryError(); return p; }; #else template T* MakeRaw(Args&&... args) { T *p = NTL_NEW_OP T(std::forward(args)...); if (!p) MemoryError(); return p; } #endif template CloneablePtr MakeCloneable(Args&&... args) { MakeCloneableAux *cp = NTL_NEW_OP MakeCloneableAux( std::forward(args)... ); if (!cp) MemoryError(); return CloneablePtr(CloneablePtrLoopHole(), &cp->d, cp); } #else // Reference forwarding template class ReferenceWrapper { private: T& x; public: ReferenceWrapper(T& _x) : x(_x) { } operator T& () const { return x; } }; template ReferenceWrapper Fwd(T& x) { return ReferenceWrapper(x); } template class ConstReferenceWrapper { private: T& x; public: ConstReferenceWrapper(const T& _x) : x(_x) { } operator const T& () const { return x; } }; template ConstReferenceWrapper Fwd(const T& x) { return ConstReferenceWrapper(x); } template T& UnwrapReference(const ReferenceWrapper& x) { return x; } template const T& UnwrapReference(const ConstReferenceWrapper& x) { return x; } template const T& UnwrapReference(const T& x) { return x; } // Some useful macros for simulating variadic templates #define NTL_REPEATER_0(m) #define NTL_REPEATER_1(m) m(1) #define NTL_REPEATER_2(m) m(1),m(2) #define NTL_REPEATER_3(m) m(1),m(2),m(3) #define NTL_REPEATER_4(m) m(1),m(2),m(3),m(4) #define NTL_REPEATER_5(m) m(1),m(2),m(3),m(4),m(5) #define NTL_REPEATER_6(m) m(1),m(2),m(3),m(4),m(5),m(6) #define NTL_REPEATER_7(m) m(1),m(2),m(3),m(4),m(5),m(6),m(7) #define NTL_REPEATER_8(m) m(1),m(2),m(3),m(4),m(5),m(6),m(7),m(8) #define NTL_REPEATER_9(m) m(1),m(2),m(3),m(4),m(5),m(6),m(7),m(8),m(9) #define NTL_SEPARATOR_0 #define NTL_SEPARATOR_1 , #define NTL_SEPARATOR_2 , #define NTL_SEPARATOR_3 , #define NTL_SEPARATOR_4 , #define NTL_SEPARATOR_5 , #define NTL_SEPARATOR_6 , #define NTL_SEPARATOR_7 , #define NTL_SEPARATOR_8 , #define NTL_SEPARATOR_9 , #define NTL_KEEP_NONZERO_0(x) #define NTL_KEEP_NONZERO_1(x) x #define NTL_KEEP_NONZERO_2(x) x #define NTL_KEEP_NONZERO_3(x) x #define NTL_KEEP_NONZERO_4(x) x #define NTL_KEEP_NONZERO_5(x) x #define NTL_KEEP_NONZERO_6(x) x #define NTL_KEEP_NONZERO_7(x) x #define NTL_KEEP_NONZERO_8(x) x #define NTL_KEEP_NONZERO_9(x) x #define NTL_FOREACH_ARG(m) \ m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) #define NTL_FOREACH_ARG1(m) \ m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) // ******************************** #define NTL_ARGTYPE(n) class X##n #define NTL_ARGTYPES(n) NTL_REPEATER_##n(NTL_ARGTYPE) #define NTL_MORE_ARGTYPES(n) NTL_SEPARATOR_##n NTL_REPEATER_##n(NTL_ARGTYPE) #define NTL_VARARG(n) const X##n & x##n #define NTL_VARARGS(n) NTL_REPEATER_##n(NTL_VARARG) #define NTL_PASSTYPE(n) X ## n #define NTL_PASSTYPES(n) NTL_REPEATER_##n(NTL_PASSTYPE) #define NTL_MORE_PASSTYPES(n) NTL_SEPARATOR_##n NTL_REPEATER_##n(NTL_PASSTYPE) #define NTL_PASSARG(n) x ## n #define NTL_PASSARGS(n) NTL_REPEATER_##n(NTL_PASSARG) #define NTL_UNWRAPARG(n) UnwrapReference(x ## n) #define NTL_UNWRAPARGS(n) NTL_REPEATER_##n(NTL_UNWRAPARG) // ******************************** #if 0 #define NTL_DEFINE_MAKESMART(n) \ template \ class MakeSmartAux##n : public SmartPtrControl {\ public: T d; \ MakeSmartAux##n( NTL_VARARGS(n) ) : \ d( NTL_UNWRAPARGS(n) ) { }\ };\ \ template\ SmartPtr MakeSmart( NTL_VARARGS(n) ) { \ MakeSmartAux##n *cp = \ NTL_NEW_OP MakeSmartAux##n( NTL_PASSARGS(n) ); \ if (!cp) MemoryError();\ return SmartPtr(SmartPtrLoopHole(), &cp->d, cp);\ };\ NTL_FOREACH_ARG(NTL_DEFINE_MAKESMART) #elif 1 // alternative implementation #define NTL_DEFINE_SMART_CONSTRUCTOR(n) \ NTL_KEEP_NONZERO_##n(template< NTL_ARGTYPES(n) >) \ MakeSmartAux( NTL_VARARGS(n) ) : \ d( NTL_UNWRAPARGS(n) ) { }\ template class MakeSmartAux : public SmartPtrControl { public: T d; NTL_FOREACH_ARG(NTL_DEFINE_SMART_CONSTRUCTOR) }; #define NTL_DEFINE_MAKESMART(n) \ template\ SmartPtr MakeSmart( NTL_VARARGS(n) ) { \ MakeSmartAux *cp = \ NTL_NEW_OP MakeSmartAux( NTL_PASSARGS(n) ); \ if (!cp) MemoryError();\ return SmartPtr(SmartPtrLoopHole(), &cp->d, cp);\ };\ NTL_FOREACH_ARG(NTL_DEFINE_MAKESMART) #else // alternative implementation #define NTL_DEFINE_MAKESMART(n) \ template \ class MakeSmartAux##n : public SmartPtrControl {\ public: T d; \ NTL_KEEP_NONZERO_##n(template< NTL_ARGTYPES(n) >) \ MakeSmartAux##n( NTL_VARARGS(n) ) : \ d( NTL_UNWRAPARGS(n) ) { }\ };\ \ template\ SmartPtr MakeSmart( NTL_VARARGS(n) ) { \ MakeSmartAux##n *cp = \ NTL_NEW_OP MakeSmartAux##n( NTL_PASSARGS(n) ); \ if (!cp) MemoryError();\ return SmartPtr(SmartPtrLoopHole(), &cp->d, cp);\ };\ NTL_FOREACH_ARG(NTL_DEFINE_MAKESMART) #endif // ******************************** #define NTL_DEFINE_MAKECLONEABLE(n) \ template \ class MakeCloneableAux##n : public CloneablePtrControl {\ public: T d; \ MakeCloneableAux##n( NTL_VARARGS(n) ) : \ d( NTL_UNWRAPARGS(n) ) { }\ CloneablePtrControl *clone() const \ {\ CloneablePtrControl *q = NTL_NEW_OP CloneablePtrControlDerived(d);\ if (!q) MemoryError();\ return q;\ }\ void *get() { return &d; }\ };\ \ template\ CloneablePtr MakeCloneable( NTL_VARARGS(n) ) { \ MakeCloneableAux##n *cp = \ NTL_NEW_OP MakeCloneableAux##n( NTL_PASSARGS(n) ); \ if (!cp) MemoryError();\ return CloneablePtr(CloneablePtrLoopHole(), &cp->d, cp);\ };\ NTL_FOREACH_ARG(NTL_DEFINE_MAKECLONEABLE) // ******************************** #ifdef NTL_TEST_EXCEPTIONS #define NTL_DEFINE_MAKERAW(n)\ template\ T* MakeRaw(NTL_VARARGS(n)) { \ T *p = 0; \ if (--exception_counter != 0) p = NTL_NEW_OP T(NTL_UNWRAPARGS(n)); \ if (!p) MemoryError();\ return p;\ };\ #else #define NTL_DEFINE_MAKERAW(n)\ template\ T* MakeRaw(NTL_VARARGS(n)) { \ T *p = NTL_NEW_OP T(NTL_UNWRAPARGS(n)); \ if (!p) MemoryError();\ return p;\ };\ #endif NTL_FOREACH_ARG(NTL_DEFINE_MAKERAW) #endif // ******************************** #ifdef NTL_TEST_EXCEPTIONS template T *MakeRawArray(long n) { if (n < 0) LogicError("negative length in MakeRawArray"); if (n == 0) return 0; T *p = 0; if (--exception_counter != 0) p = new T[n]; if (!p) MemoryError(); return p; } #else template T *MakeRawArray(long n) { if (n < 0) LogicError("negative length in MakeRawArray"); if (n == 0) return 0; T *p = new T[n]; if (!p) MemoryError(); return p; } #endif /********************************************************************** UniquePtr -- unique pointer to object with copying disabled. Useful for pointers inside classes so that we can automatically destruct them. Constructors: UniquePtr p1; // initialize with null UniquePtr p1(0); T* rp; UniquePtr p1(rp); // construct using raw pointer (explicit) p1 = 0; // destroy's p1's referent and assigns null p1.make(...); // destroy's p1's referent and assigns // a fresh objected constructed via T(...), // using psuedo variadic templates p1.reset(rp); // destroy's p1's referent and assign rp if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... *p1 // dereferencing p1->... rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to NULL p1.move(p2); // equivalent to p1.reset(p2.release()) -- // if p1 != p2 then: // makes p1 point to p2's referent, // setting p2 to NULL and destroying // p1's referent p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class UniquePtr { private: T *dp; class Dummy { }; typedef void (UniquePtr::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (UniquePtr::*fake_null_type1)(Dummy1) const; bool cannot_compare_these_types() const { return false; } UniquePtr(const UniquePtr&); // disabled void operator=(const UniquePtr&); // disabled public: explicit UniquePtr(T *p) : dp(p) { } UniquePtr() : dp(0) { } ~UniquePtr() { P::deleter(dp); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) UniquePtr(UniquePtr&& other) noexcept : UniquePtr() { this->move(other); } UniquePtr& operator=(UniquePtr&& other) noexcept { this->move(other); return *this; } #endif void reset(T* p = 0) { UniquePtr tmp(p); tmp.swap(*this); } UniquePtr& operator=(fake_null_type1) { reset(); return *this; } #if (NTL_CXX_STANDARD >= 2011) template void make(Args&&... args) { reset(MakeRaw(std::forward(args)...)); } #else void make() { reset(MakeRaw()); } #define NTL_DEFINE_UNIQUE_MAKE(n) \ template< NTL_ARGTYPES(n) >\ void make( NTL_VARARGS(n) )\ {\ reset(MakeRaw( NTL_PASSARGS(n) ));\ }\ NTL_FOREACH_ARG1(NTL_DEFINE_UNIQUE_MAKE) #endif T& operator*() const { return *dp; } T* operator->() const { return dp; } T* get() const { return dp; } T* release() { T *p = dp; dp = 0; return p; } void move(UniquePtr& other) { reset(other.release()); } void swap(UniquePtr& other) { _ntl_swap(dp, other.dp); } operator fake_null_type() const { return dp ? &UniquePtr::fake_null_function : 0; } }; template NTL_DECLARE_RELOCATABLE((UniquePtr*)) // free swap function template void swap(UniquePtr& p, UniquePtr& q) { p.swap(q); } // Equality testing template bool operator==(const UniquePtr& a, const UniquePtr& b) { return a.get() == b.get(); } template bool operator!=(const UniquePtr& a, const UniquePtr& b) { return a.get() != b.get(); } // the following definitions of == and != prevent comparisons // on UniquePtr's to different types...such comparisons // don't make sense...defining these here ensures the compiler // emits an error message...and a pretty readable one template bool operator==(const UniquePtr& a, const UniquePtr& b) { return a.cannot_compare_these_types(); } template bool operator!=(const UniquePtr& a, const UniquePtr& b) { return a.cannot_compare_these_types(); } /********************************************************************** CopiedPtr: identical interface to UniquePtr, but copy constructor and assignment are defined, and both are implemented using the underlying type's copy constructor This provides very similar functionilty to OptionalVal, but I think it is simpler to provide the same interface as UniquePtr. It also allows some fine control of deleting and copying. This allows for "clone on copy" as well as other things, like a copying or cloning PIMPL pattern. **********************************************************************/ struct DefaultCopierPolicy { template static T* copier(T *p) { return (p ? MakeRaw(*p) : 0); } }; struct CloningCopier { template static T* copier(T *p) { return (p ? p->clone() : 0); } }; struct DefaultCopiedPtrPolicy : DefaultDeleterPolicy, DefaultCopierPolicy { }; struct CloningCopiedPtrPolicy : DefaultDeleterPolicy, CloningCopier { }; template class CopiedPtr { private: T *dp; class Dummy { }; typedef void (CopiedPtr::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (CopiedPtr::*fake_null_type1)(Dummy1) const; bool cannot_compare_these_types() const { return false; } public: explicit CopiedPtr(T *p) : dp(p) { } CopiedPtr() : dp(0) { } CopiedPtr(const CopiedPtr& other) : dp(0) { reset(P::copier(other.dp)); } CopiedPtr& operator=(const CopiedPtr& other) { if (this == &other) return *this; CopiedPtr tmp(other); tmp.swap(*this); return *this; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) CopiedPtr(CopiedPtr&& other) noexcept : CopiedPtr() { this->move(other); } CopiedPtr& operator=(CopiedPtr&& other) noexcept { this->move(other); return *this; } #endif ~CopiedPtr() { P::deleter(dp); } void reset(T* p = 0) { CopiedPtr tmp(p); tmp.swap(*this); } CopiedPtr& operator=(fake_null_type1) { reset(); return *this; } #if (NTL_CXX_STANDARD >= 2011) template void make(Args&&... args) { reset(MakeRaw(std::forward(args)...)); } #else void make() { reset(MakeRaw()); } #define NTL_DEFINE_COPIED_MAKE(n) \ template< NTL_ARGTYPES(n) >\ void make( NTL_VARARGS(n) )\ {\ reset(MakeRaw( NTL_PASSARGS(n) ));\ }\ NTL_FOREACH_ARG1(NTL_DEFINE_COPIED_MAKE) #endif T& operator*() const { return *dp; } T* operator->() const { return dp; } T* get() const { return dp; } T* release() { T *p = dp; dp = 0; return p; } void move(CopiedPtr& other) { reset(other.release()); } void swap(CopiedPtr& other) { _ntl_swap(dp, other.dp); } operator fake_null_type() const { return dp ? &CopiedPtr::fake_null_function : 0; } }; template NTL_DECLARE_RELOCATABLE((CopiedPtr*)) // free swap function template void swap(CopiedPtr& p, CopiedPtr& q) { p.swap(q); } // Equality testing template bool operator==(const CopiedPtr& a, const CopiedPtr& b) { return a.get() == b.get(); } template bool operator!=(const CopiedPtr& a, const CopiedPtr& b) { return a.get() != b.get(); } // the following definitions of == and != prevent comparisons // on CopiedPtr's to different types...such comparisons // don't make sense...defining these here ensures the compiler // emits an error message...and a pretty readable one template bool operator==(const CopiedPtr& a, const CopiedPtr& b) { return a.cannot_compare_these_types(); } template bool operator!=(const CopiedPtr& a, const CopiedPtr& b) { return a.cannot_compare_these_types(); } /********************************************************************** OptionalVal -- unique pointer to object with copying enabled. Constructors: OptionalVal p1; // initialize with null T* rp; OptionalVal p1(rp); // construct using raw pointer (explicit) OptionalVal p2(p1); // construct a copy of p1's referrent p1.make(...); // destroy's p1's referent and assigns // a fresh objected constructed via T(...), // using psuedo variadic templates p1.reset(rp); // destroy's p1's referent and assign rp if (p1.exists()) ... // test for null p1.val() // dereference rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to NULL p1.move(p2); // if p1 != p2 then: // makes p1 point to p2's referent, // setting p2 to NULL and destroying // p1's referent p1 = p2; // if p1 != p2 then // if p2 == NULL then // reset p1 // else // p1.make(p2.val()) p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class OptionalVal { private: UniquePtr dp; public: explicit OptionalVal(T *p) : dp(p) { } OptionalVal() { } OptionalVal(const OptionalVal& other) { if (other.exists()) make(other.val()); } OptionalVal& operator=(const OptionalVal& other) { if (this == &other) return *this; OptionalVal tmp(other); tmp.swap(*this); return *this; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) OptionalVal(OptionalVal&& other) noexcept : OptionalVal() { this->move(other); } OptionalVal& operator=(OptionalVal&& other) noexcept { this->move(other); return *this; } #endif void reset(T* p = 0) { dp.reset(p); } #if (NTL_CXX_STANDARD >= 2011) template void make(Args&&... args) { dp.make(std::forward(args)...); } #else void make() { dp.make(); } #define NTL_DEFINE_OPTIONAL_VAL_MAKE(n) \ \ template< NTL_ARGTYPES(n) >\ void make( NTL_VARARGS(n) )\ {\ dp.make( NTL_PASSARGS(n) );\ }\ NTL_FOREACH_ARG1(NTL_DEFINE_OPTIONAL_VAL_MAKE) #endif T& val() const { return *dp; } bool exists() const { return dp != 0; } T* get() const { return dp.get(); } T* release() { return dp.release(); } void move(OptionalVal& other) { dp.move(other.dp); } void swap(OptionalVal& other) { dp.swap(other.dp); } }; template NTL_DECLARE_RELOCATABLE((OptionalVal*)) // free swap function template void swap(OptionalVal& p, OptionalVal& q) { p.swap(q); } /********************************************************************** UniqueArray -- unique pointer to array of objects with copying disabled. Useful for pointers inside classes so that we can automatically destruct them. Constructors: UniqueArray p1; // initialize with null UniqueArray p1(0); T* rp; UniqueArray p1(rp); // construct using raw pointer (explicit) p1 = 0; // destroy's p1's referent and assigns null p1.SetLength(n); // destroy's p1's referent and assigns // a fresh objected constructed via new T[n] p1.reset(rp); // destroy's p1's referent and assign rp if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... p1[i] // array indexing rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to NULL p1.move(p2); // equivalent to p1.reset(p2.release()) -- // if p1 != p2 then: // makes p1 point to p2's referent, // setting p2 to NULL and destroying // p1's referent p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class UniqueArray { private: T *dp; class Dummy { }; typedef void (UniqueArray::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (UniqueArray::*fake_null_type1)(Dummy1) const; bool cannot_compare_these_types() const { return false; } UniqueArray(const UniqueArray&); // disabled void operator=(const UniqueArray&); // disabled public: explicit UniqueArray(T *p) : dp(p) { } UniqueArray() : dp(0) { } ~UniqueArray() { delete[] dp; } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) UniqueArray(UniqueArray&& other) noexcept : UniqueArray() { this->move(other); } UniqueArray& operator=(UniqueArray&& other) noexcept { this->move(other); return *this; } #endif void reset(T* p = 0) { UniqueArray tmp(p); tmp.swap(*this); } UniqueArray& operator=(fake_null_type1) { reset(); return *this; } void SetLength(long n) { reset( MakeRawArray(n) ); } T& operator[](long i) const { return dp[i]; } T* get() const { return dp; } T *elts() const { return dp; } T* release() { T *p = dp; dp = 0; return p; } void move(UniqueArray& other) { reset(other.release()); } void swap(UniqueArray& other) { _ntl_swap(dp, other.dp); } operator fake_null_type() const { return dp ? &UniqueArray::fake_null_function : 0; } }; template NTL_DECLARE_RELOCATABLE((UniqueArray*)) // free swap function template void swap(UniqueArray& p, UniqueArray& q) { p.swap(q); } // Equality testing template bool operator==(const UniqueArray& a, const UniqueArray& b) { return a.get() == b.get(); } template bool operator!=(const UniqueArray& a, const UniqueArray& b) { return a.get() != b.get(); } // the following definitions of == and != prevent comparisons // on UniqueArray's to different types...such comparisons // don't make sense...defining these here ensures the compiler // emits an error message...and a pretty readable one template bool operator==(const UniqueArray& a, const UniqueArray& b) { return a.cannot_compare_these_types(); } template bool operator!=(const UniqueArray& a, const UniqueArray& b) { return a.cannot_compare_these_types(); } /********************************************************************** Unique2DArray -- unique pointer to array of arrays. This is very similar to UniqueArray< UniqueArray >, except that we can retrofit old code that excepts objects of type T**. Constructors: Unique2DArray p1; // initialize with null Unique2DArray p1(0); p1 = 0; // destroy's p1's referent and assigns null p1.reset(); p1.SetLength(n); // destroy's p1's referent and assigns // a fresh array of null pointers p1.SetDims(n, m) // creates an n x m array if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... p1[i] // array indexing T **rp; rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to NULL p1.move(p2); // if p1 != p2 then: // makes p1 point to p2's referent, // setting p2 to NULL and destroying // p1's referent p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class Unique2DArray { public: typedef T *T_ptr; private: UniqueArray dp; long len; class Dummy { }; typedef void (Unique2DArray::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (Unique2DArray::*fake_null_type1)(Dummy1) const; bool cannot_compare_these_types() const { return false; } Unique2DArray(const Unique2DArray&); // disabled void operator=(const Unique2DArray&); // disabled public: Unique2DArray() : len(0) { } ~Unique2DArray() { if (dp) { long i; for (i = 0; i < len; i++) delete [] dp[i]; } } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) Unique2DArray(Unique2DArray&& other) noexcept : Unique2DArray() { this->move(other); } Unique2DArray& operator=(Unique2DArray&& other) noexcept { this->move(other); return *this; } #endif void reset() { Unique2DArray tmp; tmp.swap(*this); } Unique2DArray& operator=(fake_null_type1) { reset(); return *this; } void SetLength(long n) { UniqueArray tmp; tmp.SetLength(n); long i; for (i = 0; i < n; i++) tmp[i] = 0; reset(); dp.move(tmp); len = n; } // EXCEPTIONS: strong ES void SetDims(long n, long m) { Unique2DArray tmp; tmp.SetLength(n); long i; for (i = 0; i < n; i++) tmp[i] = MakeRawArray(m); this->move(tmp); } // EXCEPTIONS: strong ES // This is a special-purpose routine to help // with some legacy code...only rows 1..n-1 are allocated void SetDimsFrom1(long n, long m) { Unique2DArray tmp; tmp.SetLength(n); long i; for (i = 1; i < n; i++) tmp[i] = MakeRawArray(m); this->move(tmp); } T_ptr& operator[](long i) const { return dp[i]; } T_ptr* get() const { return dp.get(); } T_ptr* release() { len = 0; return dp.release(); } void move(Unique2DArray& other) { Unique2DArray tmp; tmp.swap(other); tmp.swap(*this); } void swap(Unique2DArray& other) { dp.swap(other.dp); _ntl_swap(len, other.len); } operator fake_null_type() const { return dp ? &Unique2DArray::fake_null_function : 0; } }; template NTL_DECLARE_RELOCATABLE((Unique2DArray*)) // free swap function template void swap(Unique2DArray& p, Unique2DArray& q) { p.swap(q); } // Equality testing template bool operator==(const Unique2DArray& a, const Unique2DArray& b) { return a.get() == b.get(); } template bool operator!=(const Unique2DArray& a, const Unique2DArray& b) { return a.get() != b.get(); } // the following definitions of == and != prevent comparisons // on Unique2DArray's to different types...such comparisons // don't make sense...defining these here ensures the compiler // emits an error message...and a pretty readable one template bool operator==(const Unique2DArray& a, const Unique2DArray& b) { return a.cannot_compare_these_types(); } template bool operator!=(const Unique2DArray& a, const Unique2DArray& b) { return a.cannot_compare_these_types(); } // AlignedArray: // // specialized arrays that have similar interface to UniqueArray, but: // * they are allocated with a given alignment // * they (currently) only work on POD types // // DIRT: // The current implementation just uses the _ntl_make_aligned function, // which is not entirely portable. // However, AlignedArray is currently only used if NTL_HAVE_AVX // is defined, and under the assumptions imposed with that, // it should definitely work. // // For now, this is not a part of the documented interface. // This could all change in the future, if and when there is a more portable // way of doing this. template class AlignedArray { private: T *dp; char *sp; class Dummy { }; typedef void (AlignedArray::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} class Dummy1 { }; typedef void (AlignedArray::*fake_null_type1)(Dummy1) const; bool cannot_compare_these_types() const { return false; } AlignedArray(const AlignedArray&); // disabled void operator=(const AlignedArray&); // disabled char* release() { char *p = sp; dp = 0; sp = 0; return p; } void reset(char* p) { AlignedArray tmp; if (p) { tmp.dp = (T*) _ntl_make_aligned(p, align); tmp.sp = p; } else { tmp.dp = 0; tmp.sp = 0; } tmp.swap(*this); } public: AlignedArray() : dp(0), sp(0) { } explicit AlignedArray(fake_null_type1) : dp(0), sp(0) { } ~AlignedArray() { NTL_SNS free(sp); } #if (NTL_CXX_STANDARD >= 2011 && !defined(NTL_DISABLE_MOVE)) AlignedArray(AlignedArray&& other) noexcept : AlignedArray() { this->move(other); } AlignedArray& operator=(AlignedArray&& other) noexcept { this->move(other); return *this; } #endif void reset() { reset(0); } AlignedArray& operator=(fake_null_type1) { reset(); return *this; } void SetLength(long n) { if (align <= 0 || n < 0) LogicError("AlignedArray::SetLength: bad args"); if (NTL_OVERFLOW1(n, sizeof(T), align)) ResourceError("AlignedArray::SetLength: overflow"); if (n == 0) { reset(); } else { char *p = (char *) NTL_SNS malloc(n*sizeof(T) + align); if (!p) MemoryError(); reset(p); } } T& operator[](long i) const { return dp[i]; } T* get() const { return dp; } T* elts() const { return dp; } void move(AlignedArray& other) { reset(other.release()); } void swap(AlignedArray& other) { _ntl_swap(dp, other.dp); _ntl_swap(sp, other.sp); } operator fake_null_type() const { return dp ? &AlignedArray::fake_null_function : 0; } }; template NTL_DECLARE_RELOCATABLE((AlignedArray*)) // free swap function template void swap(AlignedArray& p, AlignedArray& q) { p.swap(q); } NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/Lazy.h0000644417616742025610000001161114064716022017325 0ustar gid-shoupvpug-gid-shoupv /*************************************************************************** Lazy: template class for lazy initialization of objects whose values do not change after initialization. In a multi-threaded environment, this makes use of "double checked locking" for an efficient, thread-safe solution. Usage: Lazy obj; // declaration of the lazy object ... do { Lazy::Builder builder(obj); if (!builder()) break; // if we are not building, the break out UniquePtr p; // create a pointer ... builder.move(p); // move p into the object to complete the initialization // We can then complete the initialization process. } while(0); // When this scope closes, the object is fully initialized. // subsequent attempts to build the object will yield // !builder.built() T objCopy = *obj; // *obj returns a read-only reference // one can also use -> operator It is important to follow this recipe carefully. In particular, the builder must be enclosed in a scope, as it's destructor plays a crucial role in finalizing the initialization. NOTE: if p is null in builder.move(p), the object is still considered built. template class Lazy { public: Lazy(); Lazy(const Lazy&); // "deep" copies Lazy& operator=(const Lazy&); const T& operator*() const; // pointer access const T* operator->() const; const T* get() const; operator fake_null_type() const; // test for null pointer ~Lazy(); kill(); // destroy and reset bool built() const; // test if already built class Builder { Builder(const Lazy&); ~Builder() bool operator()() const; // test if we are building void move(UniquePtr&); }; ****************************************************************************/ #ifndef NTL_Lazy__H #define NTL_Lazy__H #include #include #include NTL_OPEN_NNS // NOTE: For more on double-checked locking, see // http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ // NOTE: when compiled with the NTL_THREADS option, the Lazy // class may contain data members from the standard library // that may not satisfy the requirements of the Vec class // (i.e., relocatability). One can wrap it in a pointer // class (e.g., OptionalVal) to deal with this. template class Lazy { private: /* we make data members mutable so that Lazy members of other classes don't have to be. */ mutable AtomicBool initialized; mutable MutexProxy mtx; mutable UniquePtr data; class Dummy { }; typedef void (Lazy::*fake_null_type)(Dummy) const; void fake_null_function(Dummy) const {} public: Lazy() : initialized(false) { } // EXCEPTIONS: This always succeeds in killing the object void kill() { UniquePtr tmp; tmp.swap(data); initialized = false; } // This is provided for convenience for some legacy code. // It us up to the client code to ensure there are no race conditions. // EXCEPTIONS: strong ES Lazy& operator=(const Lazy& other) { if (this == &other) return *this; if (other.initialized) { UniquePtr p; if (other.data) p.make(*other.data); p.swap(data); initialized = true; } else kill(); return *this; } Lazy(const Lazy& other) : initialized(false) { *this = other; } const T& operator*() const { return *data; } const T* operator->() const { return data.operator->(); } const T* get() const { return data.get(); } bool built() const { return initialized; } operator fake_null_type() const { return data ? &Lazy::fake_null_function : 0; } class Builder { private: bool building; bool moved; const Lazy& ref; GuardProxy guard; Builder(const Builder&); // disabled void operator=(const Builder&); // disabled public: Builder(const Lazy& _ref) : building(false), moved(false), ref(_ref), guard(_ref.mtx) { // Double-checked locking if (ref.initialized || (guard.lock(), ref.initialized)) return; building = true; // we set this to true after we lock the mutex // and see the the object is still uninitialized } ~Builder() { if (moved) ref.initialized = true; } void move(UniquePtr& p) { if (!building || moved) LogicError("Lazy::Builder illegal call to move"); ref.data.move(p); moved = true; } bool operator()() const { return building; } }; }; // NOTE: Lazy's are non-relocatable NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/LazyTable.h0000644417616742025610000000732014064716022020277 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_LazyTable__H #define NTL_LazyTable__H #include #include #include NTL_OPEN_NNS /*************************************************************************** LazyTable: template class for lazy initialization of objects whose values do not change after initialization. In a multi-threaded environment, this makes use of "double checked locking" for an efficient, thread-safe solution. Usage: LazyTable tab; // declaration of the lazy table, with max size == MAX ... do { LazyTable::Builder builder(tab, n); // request length n long amt = builder.amt(); if (!amt) break; ... initialize elements i = n-amt..n-1 using builder.move(p), where p is a UnqiuePtr note that each move application appends one element } while(0); // When this scope closes, // the table is fully initialized to length n const T* val = table[i]; // read-only access to table elements 0..n-1 It is important to follow this recipe carefully. In particular, the builder must be enclosed in a scope, as it's destructor plays a crucial role in finalizing the initialization. template class LazyTable { public: LazyTable(); const T * operator[] (long i) const; ~LazyTable(); long length() const; class Builder { Builder(const LazyTable&, long request); ~Builder() long amt() const; void move(UniquePtr& p); private: LazyTable(const LazyTable&); // disabled LazyTable& operator=(const LazyTable&); }; ****************************************************************************/ // NOTE: For more on double-checked locking, see // http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ // NOTE: when compiled with the NTL_THREADS option, the LazyTable // class may contain data members from the standard library // that may not satisfy the requirements of the Vec class // (i.e., relocatability). One can wrap it in a pointer // class (e.g., OptionalVal) to deal with this. template class LazyTable { private: mutable AtomicLong len; mutable MutexProxy mtx; mutable UniqueArray< UniquePtr > data; LazyTable(const LazyTable&); // disabled void operator=(const LazyTable&); // disabled public: LazyTable() : len(0) { } const T * operator[] (long i) const { // FIXME: add optional range checking return data[i].get(); } long length() const { return len; } class Builder { private: const LazyTable& ref; long request; GuardProxy guard; long amount; long curlen; Builder(const Builder&); // disabled void operator=(const Builder&); // disabled public: Builder(const LazyTable& _ref, long _request) : ref(_ref), request(_request), guard(_ref.mtx), amount(0), curlen(0) { if (request < 0 || request > MAX) LogicError("request out of range in LazyTable::Builder"); // Double-checked locking if (request <= ref.len || (guard.lock(), request <= ref.len)) return; curlen = ref.len; amount = request - curlen; if (!ref.data) ref.data.SetLength(MAX); } ~Builder() { if (amount) ref.len = curlen; } void move(UniquePtr& p) { if (!amount || curlen >= request) LogicError("LazyTable::Builder illegal move"); ref.data[curlen].move(p); curlen++; } long amt() const { return amount; } }; }; // NOTE: LazyTable's are non-relocatable NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/thread.h0000644417616742025610000001441514064716022017662 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_thread__H #define NTL_thread__H #include #include #ifdef NTL_THREADS #include #include #endif NTL_OPEN_NNS #ifdef NTL_THREADS class AtomicLong { private: NTL_SNS atomic_long data; AtomicLong(const AtomicLong& other); // disabled AtomicLong& operator=(const AtomicLong& other); // disabled public: explicit AtomicLong(const long& _data) : data(_data) { } AtomicLong& operator=(const long& _data) { data.store(_data, NTL_SNS memory_order_release); return *this; } operator long() const { return data.load( NTL_SNS memory_order_acquire); } }; class AtomicLowWaterMark { private: NTL_SNS atomic_ulong data; AtomicLowWaterMark(const AtomicLowWaterMark& other); // disabled AtomicLowWaterMark& operator=(const AtomicLowWaterMark& other); // disabled public: explicit AtomicLowWaterMark(const unsigned long& _data) : data(_data) { } operator unsigned long() const { return data.load( NTL_SNS memory_order_relaxed); } void UpdateMin(unsigned long val) { unsigned long old_data = *this; while(old_data > val && !data.compare_exchange_weak(old_data, val, NTL_SNS memory_order_relaxed)); // NOTE: there have been some bug reports for GCC, CLANG, and MSVC // on the implementation of compare_exchange_weak. // For a great introduction to compare_exchange_weak, see // http://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ // In fact, almost everything I known about C++11 atomics I learned // from Preshing's blog. For more on the compiler bug, see // https://stackoverflow.com/questions/21879331/is-stdatomic-compare-exchange-weak-thread-unsafe-by-design/21946549#21946549 } }; class AtomicBool { private: NTL_SNS atomic_bool data; AtomicBool(const AtomicBool& other); // disabled AtomicBool& operator=(const AtomicBool& other); // disabled public: explicit AtomicBool(const bool& _data) : data(_data) { } AtomicBool& operator=(const bool& _data) { data.store(_data, NTL_SNS memory_order_release); return *this; } operator bool() const { return data.load( NTL_SNS memory_order_acquire); } }; class AtomicCounter { private: NTL_SNS atomic_ulong cnt; public: AtomicCounter() : cnt(0) { } explicit AtomicCounter(unsigned long _cnt) : cnt(_cnt) { } unsigned long inc() { return cnt.fetch_add(1UL, NTL_SNS memory_order_relaxed); } }; class AtomicRefCount { private: NTL_SNS atomic_long cnt; public: AtomicRefCount() : cnt(0) { } void inc() { cnt.fetch_add(1, NTL_SNS memory_order_relaxed); } bool dec() { if (cnt.fetch_sub(1, NTL_SNS memory_order_release) == 1) { NTL_SNS atomic_thread_fence(NTL_SNS memory_order_acquire); return true; } else return false; } long get_count() const { return cnt; } // mainly for debugging }; class MutexProxy { private: NTL_SNS mutex mtx; MutexProxy(const MutexProxy&); // disabled void operator=(const MutexProxy&); // disabled public: MutexProxy() { } friend class GuardProxy; }; class GuardProxy { private: NTL_SNS unique_lock lck; GuardProxy(const GuardProxy&); // disabled void operator=(const GuardProxy&); // disabled public: GuardProxy(MutexProxy& mtx) : lck(mtx.mtx, NTL_SNS defer_lock) { } void lock() { lck.lock(); } }; #else class AtomicLong { private: long data; AtomicLong(const AtomicLong& other); // disabled AtomicLong& operator=(const AtomicLong& other); // disabled public: explicit AtomicLong(const long& _data) : data(_data) { } AtomicLong& operator=(const long& _data) { data = _data; return *this; } operator long() const { return data; } }; class AtomicLowWaterMark { private: unsigned long data; AtomicLowWaterMark(const AtomicLowWaterMark& other); // disabled AtomicLowWaterMark& operator=(const AtomicLowWaterMark& other); // disabled public: explicit AtomicLowWaterMark(const unsigned long& _data) : data(_data) { } operator unsigned long() const { return data; } void UpdateMin(unsigned long val) { if (val < data) data = val; } }; class AtomicBool { private: bool data; AtomicBool(const AtomicBool& other); // disabled AtomicBool& operator=(const AtomicBool& other); // disabled public: explicit AtomicBool(const bool& _data) : data(_data) { } AtomicBool& operator=(const bool& _data) { data = _data; return *this; } operator bool() const { return data; } }; class AtomicCounter { private: unsigned long cnt; AtomicCounter(const AtomicCounter&); // disabled void operator=(const AtomicCounter&); // disabled public: AtomicCounter() : cnt(0) { } explicit AtomicCounter(unsigned long _cnt) : cnt(_cnt) { } unsigned long inc() { return cnt++; } }; class AtomicRefCount { private: long cnt; AtomicRefCount(const AtomicRefCount&); // disabled void operator=(const AtomicRefCount&); // disabled public: AtomicRefCount() : cnt(0) { } void inc() { cnt++; } bool dec() { cnt--; return cnt == 0; } long get_count() const { return cnt; } // mainly for debugging }; class MutexProxy { private: MutexProxy(const MutexProxy&); // disabled void operator=(const MutexProxy&); // disabled public: MutexProxy() { } }; class GuardProxy { private: GuardProxy(const GuardProxy&); // disabled void operator=(const GuardProxy&); // disabled public: GuardProxy(MutexProxy&) { } void lock() { } }; #endif const NTL_SNS string& CurrentThreadID(); /********************************************************************* NOTES: See http://preshing.com/20120913/acquire-and-release-semantics/ http://preshing.com/20130922/acquire-and-release-fences/ http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ http://preshing.com/20131125/acquire-and-release-fences-dont-work-the-way-youd-expect/ for general information on C++11 atomics. Also see http://www.chaoticmind.net/~hcb/projects/boost.atomic/doc/atomic/usage_examples.html#boost_atomic.usage_examples.example_reference_counters for reference counting in a multi-threaded environment. *********************************************************************/ NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/BasicThreadPool.h0000644417616742025610000004603714064716022021423 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_BasicThreadPool__H #define NTL_BasicThreadPool__H #include #include #include #include NTL_OPEN_NNS inline long AvailableThreads(); struct PartitionInfo { long nintervals; // number of intervals long intervalsz; // interval size long nsintervals; // number of small intervals explicit PartitionInfo(long sz, long nt = AvailableThreads()) // partitions [0..sz) into nintervals intervals, // so that there are nsintervals of size intervalsz-1 // and nintervals-nsintervals of size intervalsz { if (sz <= 0) { nintervals = intervalsz = nsintervals = 0; return; } if (nt <= 0) LogicError("PartitionInfo: bad args"); // NOTE: this overflow check probably unnecessary if (NTL_OVERFLOW(sz, 1, 0) || NTL_OVERFLOW(nt, 1, 0)) ResourceError("PartitionInfo: arg too big"); if (sz < nt) { nintervals = sz; intervalsz = 1; nsintervals = 0; return; } nintervals = nt; long q, r; q = sz/nt; r = sz - nt*q; if (r == 0) { intervalsz = q; nsintervals = 0; } else { intervalsz = q+1; nsintervals = nt - r; } } long NumIntervals() const { return nintervals; } void interval(long& first, long& last, long i) const // [first..last) is the ith interval -- no range checking is done { #if 0 // this is the logic, naturally expressed if (i < nsintervals) { first = i*(intervalsz-1); last = first + (intervalsz-1); } else { first = nsintervals*(intervalsz-1) + (i-nsintervals)*intervalsz; last = first + intervalsz; } #else // this is the same logic, but branch-free (and portable) // ...probably unnecessary optimization long mask = -long(cast_unsigned(i-nsintervals) >> (NTL_BITS_PER_LONG-1)); // mask == -1 if i < nsintervals, 0 o/w long lfirst = i*(intervalsz-1); lfirst += long((~cast_unsigned(mask)) & cast_unsigned(i-nsintervals)); // lfirst += max(0, i-nsintervals) long llast = lfirst + intervalsz + mask; first = lfirst; last = llast; #endif } }; NTL_CLOSE_NNS #ifdef NTL_THREADS #include #include #include NTL_OPEN_NNS /************************************************************* Some simple thread pooling. You create a thread pool by constructing a BasicThreadPool object. For example: long nthreads = 4; BasicThreadPool pool(nthreads); creates a thread pool of 4 threads. These threads will exist until the destructor for pool is called. The simplest way to use a thread pools is as follows. Suppose you have a task that consists of N subtasks, indexed 0..N-1. Then you can write: pool.exec_range(N, [&](long first, long last) { for (long i = first; i < last; i++) { ... code to process subtask i ... } } ); The second argument to exec1 is a C++11 "lambda". The "[&]" indicates that all local variables in the calling context are captured by reference, so the lambda body can reference all visible local variables directly. A lower-level interface is also provided. One can write: pool.exec_index(n, [&](long index) { ... code to process index i ... } ); This will activate n threads with indices 0..n-1, and execute the given code on each index. The parameter n must be in the range 1..nthreads, otherwise an error is raised. This lower-level interface is useful in some cases, especially when memory is managed in some special way. For convenience, a method is provided to break subtasks up into smaller, almost-equal-sized groups of subtasks: Vec pvec; long n = pool.SplitProblems(N, pvec); can be used for this. N is the number of subtasks, indexed 0..N-1. This method will compute n as needed by exec, and the range of subtasks to be processed by a given index in the range 0..n-1 is pvec[index]..pvec[index+1]-1 Thus, the logic of the above exec1 example can be written using the lower-level exec interface as follows: Vec pvec; long n = pool.SplitProblems(N, pvec); pool.exec_index(n, [&](long index) { long first = pvec[index]; long last = pvec[index+1]; for (long i = first; i < last; i++) { ... code to process subtask i ... } } ); However, with this approach, memory or other resources can be assigned to each index = 0..n-1, and managed externally. *************************************************************/ class BasicThreadPool { friend struct RecursiveThreadPool; private: // lots of nested stuff template class SimpleSignal { private: T val; std::mutex m; std::condition_variable cv; SimpleSignal(const SimpleSignal&); // disabled void operator=(const SimpleSignal&); // disabled public: SimpleSignal() : val(0) { } T wait() { std::unique_lock lock(m); cv.wait(lock, [&]() { return val; } ); T old_val = val; val = 0; return old_val; } void send(T new_val) { std::lock_guard lock(m); val = new_val; cv.notify_one(); } }; template class CompositeSignal { private: T val; T1 val1; std::mutex m; std::condition_variable cv; CompositeSignal(const CompositeSignal&); // disabled void operator=(const CompositeSignal&); // disabled public: CompositeSignal() : val(0) { } T wait(T1& _val1) { std::unique_lock lock(m); cv.wait(lock, [&]() { return val; } ); T _val = val; _val1 = val1; val = 0; return _val; } void send(T _val, T1 _val1) { std::lock_guard lock(m); val = _val; val1 = _val1; cv.notify_one(); } }; class ConcurrentTask { BasicThreadPool *pool; public: ConcurrentTask(BasicThreadPool *_pool) : pool(_pool) { } BasicThreadPool *getBasicThreadPool() const { return pool; } virtual void run(long index) = 0; }; // dummy class, used for signalling termination class ConcurrentTaskTerminate : public ConcurrentTask { public: ConcurrentTaskTerminate() : ConcurrentTask(0) { } void run(long index) { } }; template class ConcurrentTaskFct : public ConcurrentTask { public: const Fct& fct; ConcurrentTaskFct(BasicThreadPool *_pool, const Fct& _fct) : ConcurrentTask(_pool), fct(_fct) { } void run(long index) { fct(index); } }; template class ConcurrentTaskFct1 : public ConcurrentTask { public: const Fct& fct; const PartitionInfo& pinfo; ConcurrentTaskFct1(BasicThreadPool *_pool, const Fct& _fct, const PartitionInfo& _pinfo) : ConcurrentTask(_pool), fct(_fct), pinfo(_pinfo) { } void run(long index) { long first, last; pinfo.interval(first, last, index); fct(first, last); } }; struct AutomaticThread { CompositeSignal< ConcurrentTask *, long > localSignal; ConcurrentTaskTerminate term; std::thread t; AutomaticThread() : t(worker, &localSignal) { // cerr << "starting thread " << t.get_id() << "\n"; } ~AutomaticThread() { // cerr << "stopping thread " << t.get_id() << "..."; localSignal.send(&term, -1); t.join(); // cerr << "\n"; } }; // BasicThreadPool data members long nthreads; bool active_flag; std::atomic counter; SimpleSignal globalSignal; Vec< UniquePtr > threadVec; std::exception_ptr eptr; std::mutex eptr_guard; // BasicThreadPool private member functions BasicThreadPool(const BasicThreadPool&); // disabled void operator=(const BasicThreadPool&); // disabled void launch(ConcurrentTask *task, long index) { threadVec[index-1]->localSignal.send(task, index); // we use threadVec[index-1] to allow for the fact // that we want the current thread to have index 0 } void begin(long cnt) { active_flag = true; counter = cnt; } void end() { globalSignal.wait(); active_flag = false; if (eptr) { std::exception_ptr eptr1 = eptr; eptr = nullptr; std::rethrow_exception(eptr1); } } static void runOneTask(ConcurrentTask *task, long index) { BasicThreadPool *pool = task->getBasicThreadPool(); try { task->run(index); } catch (...) { std::lock_guard lock(pool->eptr_guard); if (!pool->eptr) pool->eptr = std::current_exception(); } if (--(pool->counter) == 0) pool->globalSignal.send(true); } static void worker(CompositeSignal< ConcurrentTask *, long > *localSignal) { for (;;) { long index = -1; ConcurrentTask *task = localSignal->wait(index); if (index == -1) return; runOneTask(task, index); } } public: long NumThreads() const { return nthreads; } bool active() const { return active_flag; } explicit BasicThreadPool(long _nthreads) : nthreads(_nthreads), active_flag(false), counter(0) { if (nthreads <= 0) LogicError("BasicThreadPool::BasicThreadPool: bad args"); if (nthreads == 1) return; if (NTL_OVERFLOW(nthreads, 1, 0)) ResourceError("BasicThreadPool::BasicThreadPool: arg too big"); threadVec.SetLength(nthreads-1); for (long i = 0; i < nthreads-1; i++) { threadVec[i].make(); } } ~BasicThreadPool() { if (active()) TerminalError("BasicThreadPool: destructor called while active"); } // adding, deleting, moving threads void add(long n = 1) { if (active()) LogicError("BasicThreadPool: illegal operation while active"); if (n <= 0) LogicError("BasicThreadPool::add: bad args"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("BasicThreadPool::add: arg too big"); Vec< UniquePtr > newThreads; newThreads.SetLength(n); for (long i = 0; i < n; i++) newThreads[i].make(); threadVec.SetLength(n + nthreads - 1); for (long i = 0; i < n; i++) threadVec[nthreads-1+i].move(newThreads[i]); nthreads += n; } void remove(long n = 1) { if (active()) LogicError("BasicThreadPool: illegal operation while active"); if (n <= 0 || n >= nthreads) LogicError("BasicThreadPool::remove: bad args"); for (long i = nthreads-1-n; i < nthreads-1; i++) threadVec[i] = 0; threadVec.SetLength(nthreads-1-n); nthreads -= n; } void move(BasicThreadPool& other, long n = 1) { if (active() || other.active()) LogicError("BasicThreadPool: illegal operation while active"); if (n <= 0 || n >= other.nthreads) LogicError("BasicThreadPool::move: bad args"); if (this == &other) return; threadVec.SetLength(n + nthreads - 1); for (long i = 0; i < n; i++) threadVec[nthreads-1+i].move(other.threadVec[other.nthreads-1-n+i]); other.threadVec.SetLength(other.nthreads-1-n); other.nthreads -= n; nthreads += n; } // High level interfaces, intended to be used with lambdas // In this version, fct takes one argument, which is // an index in [0..cnt) template void exec_index(long cnt, const Fct& fct) { if (active()) LogicError("BasicThreadPool: illegal operation while active"); if (cnt <= 0) return; if (cnt > nthreads) LogicError("BasicThreadPool::exec_index: bad args"); ConcurrentTaskFct task(this, fct); begin(cnt); for (long t = 1; t < cnt; t++) launch(&task, t); runOneTask(&task, 0); end(); } template static void relaxed_exec_index(BasicThreadPool *pool, long cnt, const Fct& fct) { if (cnt > 0) { if (cnt == 1) { fct(0); } else if (pool && !pool->active()) { pool->exec_index(cnt, fct); } else { LogicError("relaxed_exec_index: not enough threads"); } } } // even higher level version: sz is the number of subproblems, // and fct takes two args, first and last, so that subproblems // [first..last) are processed. template void exec_range(long sz, const Fct& fct) { if (active()) LogicError("BasicThreadPool: illegal operation while active"); if (sz <= 0) return; PartitionInfo pinfo(sz, nthreads); long cnt = pinfo.NumIntervals(); ConcurrentTaskFct1 task(this, fct, pinfo); begin(cnt); for (long t = 1; t < cnt; t++) launch(&task, t); runOneTask(&task, 0); end(); } template static void relaxed_exec_range(BasicThreadPool *pool, long sz, const Fct& fct) { if (sz <= 0) return; if (!pool || pool->active() || sz == 1) { fct(0, sz); } else { pool->exec_range(sz, fct); } } }; // NOTE: BasicThreadPool's are non-relocatable struct RecursiveThreadPool : BasicThreadPool { BasicThreadPool *base_pool; long lo, hi; // range of indices is [lo..hi) RecursiveThreadPool(BasicThreadPool* _base_pool, long _lo, long _hi) : BasicThreadPool(1), base_pool(_base_pool), lo(_lo), hi(_hi) { if (lo == 0 && hi == base_pool->nthreads) base_pool->active_flag = true; } ~RecursiveThreadPool() { if (lo == 0 && hi == base_pool->nthreads) base_pool->active_flag = false; } template void exec_pair(long mid, const Fct0& fct0, const Fct1& fct1) { ConcurrentTaskFct task0(this, fct0); ConcurrentTaskFct task1(this, fct1); begin(2); base_pool->launch(&task1, mid); runOneTask(&task0, lo); end(); } }; // NOTE: RecursiveThreadPool's are non-relocatable inline SmartPtr StartRecursion(BasicThreadPool *base_pool) { if (!base_pool || base_pool->active()) return 0; long nthreads = base_pool->NumThreads(); if (nthreads <= 1) return 0; return MakeSmart(base_pool, 0, nthreads); } // NOTE: returning some kind of smart pointer ensures that // the object itself will stay alive until the end of the // largest enclosing expression, and then be destroyed. // I could have also used a UniquePtr, and relied on the move // constructor to be called. However, NTL still has a DISABLE_MOVE // option that would break that. I could also have used // std::unique_ptr; however, I'm generally avoiding those parts // of the standard library. A SmartPtr has some additional // overhead, but this will only be called once at the outermost // recursion, so it should be OK. struct RecursiveThreadPoolHelper { UniquePtr subpool_stg[2]; RecursiveThreadPool *subpool_ptr[2]; long mid; bool concurrent() { return mid != 0; } RecursiveThreadPool* subpool(long i) { return subpool_ptr[i]; } RecursiveThreadPoolHelper(RecursiveThreadPool *pool, bool seq, double load0) { mid = 0; subpool_ptr[0] = subpool_ptr[1] = 0; if (seq || !pool) return; long n = pool->hi - pool->lo; if (n <= 1) return; long n0 = long(load0*n + 0.5); if (n0 < 0 || n0 > n) LogicError("RecursiveThreadPoolHelper: bad load0"); if (n0 == 0) { subpool_ptr[1] = pool; return; } if (n0 == n) { subpool_ptr[0] = pool; return; } mid = pool->lo + n0; long n1 = n-n0; if (n0 > 1) subpool_stg[0].make(pool->base_pool, pool->lo, mid); if (n1 > 1) subpool_stg[1].make(pool->base_pool, mid, pool->hi); subpool_ptr[0] = subpool_stg[0].get(); subpool_ptr[1] = subpool_stg[1].get(); } }; NTL_CLOSE_NNS #endif #ifdef NTL_THREAD_BOOST #ifndef NTL_THREADS #error "NTL_THREAD_BOOST requires NTL_THREADS" #endif NTL_OPEN_NNS extern NTL_CHEAP_THREAD_LOCAL BasicThreadPool *NTLThreadPool_ptr; inline BasicThreadPool *GetThreadPool() { return NTLThreadPool_ptr; } void ResetThreadPool(BasicThreadPool *pool = 0); BasicThreadPool *ReleaseThreadPool(); inline void SetNumThreads(long n) { BasicThreadPool *p = (n == 1 ? 0 : MakeRaw(n)); ResetThreadPool(p); } inline long AvailableThreads() { BasicThreadPool *pool = GetThreadPool(); if (!pool || pool->active()) return 1; else return pool->NumThreads(); } NTL_CLOSE_NNS #define NTL_EXEC_RANGE(n, first, last) \ { \ NTL_NNS BasicThreadPool::relaxed_exec_range(NTL_NNS GetThreadPool(), (n), \ [&](long first, long last) { \ #define NTL_EXEC_RANGE_END \ } ); \ } \ #define NTL_GEXEC_RANGE(seq, n, first, last) \ { \ NTL_NNS BasicThreadPool::relaxed_exec_range((seq) ? 0 : NTL_NNS GetThreadPool(), (n), \ [&](long first, long last) { \ #define NTL_GEXEC_RANGE_END \ } ); \ } \ #define NTL_EXEC_INDEX(n, index) \ { \ NTL_NNS BasicThreadPool::relaxed_exec_index(NTL_NNS GetThreadPool(), (n), \ [&](long index) { \ #define NTL_EXEC_INDEX_END \ } ); \ } \ // NOTE: at least with gcc >= 4.9.2, the GEXEC versions will evaluate seq, and // if it is true, jump directly (more or less) to the body #define NTL_TBDECL(x) static void basic_ ## x #define NTL_TBDECL_static(x) static void basic_ ## x #define NTL_IMPORT(x) auto _ntl_hidden_variable_IMPORT__ ## x = x; auto x = _ntl_hidden_variable_IMPORT__ ##x; #define NTL_INIT_DIVIDE StartRecursion(GetThreadPool()).get() #define NTL_EXEC_DIVIDE(seq, pool, helper, load0, F0, F1) \ { \ NTL::RecursiveThreadPoolHelper helper(pool, seq, load0); \ if (!helper.mid) { \ { F0; } \ { F1; } \ } \ else { \ pool->exec_pair(helper.mid, \ [&](long){ F0; }, \ [&](long){ F1; } ); \ } \ } #else NTL_OPEN_NNS inline void SetNumThreads(long n) { } inline long AvailableThreads() { return 1; } struct RecursiveThreadPool; struct RecursiveThreadPoolDummyHelper { bool concurrent() { return false; } RecursiveThreadPool* subpool(long i) { return 0; } }; NTL_CLOSE_NNS #define NTL_EXEC_RANGE(n, first, last) \ { \ long _ntl_par_exec_n = (n); \ if (_ntl_par_exec_n > 0) { \ long first = 0; \ long last = _ntl_par_exec_n; \ { \ #define NTL_EXEC_RANGE_END }}} #define NTL_GEXEC_RANGE(seq, n, first, last) \ { \ long _ntl_par_exec_n = (n); \ if (_ntl_par_exec_n > 0) { \ long first = 0; \ long last = _ntl_par_exec_n; \ { \ #define NTL_GEXEC_RANGE_END }}} #define NTL_EXEC_INDEX(n, index) \ { \ long _ntl_par_exec_n = (n); \ if (_ntl_par_exec_n > 0) { \ if (_ntl_par_exec_n > 1) NTL_NNS LogicError("NTL_EXEC_INDEX: not enough threads"); \ long index = 0; \ { \ #define NTL_EXEC_INDEX_END }}} #define NTL_TBDECL(x) void x #define NTL_TBDECL_static(x) static void x #define NTL_IMPORT(x) #define NTL_INIT_DIVIDE ((RecursiveThreadPool*) 0) #define NTL_EXEC_DIVIDE(seq, pool, helper, load0, F0, F1) \ { \ NTL::RecursiveThreadPoolDummyHelper helper; \ { F0; } \ { F1; } \ } #endif #endif ntl-11.5.1/include/NTL/MatPrime.h0000644417616742025610000000643614064716022020135 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_MatPrime__H #define NTL_MatPrime__H #include #include #include #include #include #include NTL_OPEN_NNS #define NTL_MatPrimeFudge (3) // similar to the FFTPrime strategy...ensures // we can use floating point to approximate a quotient #define NTL_MatPrimeLimit (1L << 20) // Limit on dimension for matrix mul #ifdef NTL_HAVE_AVX #define NTL_MatPrime_NBITS (23) #else #define NTL_MatPrime_NBITS NTL_SP_NBITS #endif #if (NTL_MatPrime_NBITS > NTL_SP_NBITS) // This is mainly academic #define NTL_MatPrime_NBITS NTL_SP_NBITS #endif #if (NTL_MatPrime_NBITS < NTL_BITS_PER_INT) typedef int MatPrime_residue_t; #else typedef long MatPrime_residue_t; #endif #if (2*NTL_MatPrime_NBITS+1 <= NTL_SP_NBITS) #define NTL_MatPrime_HALF_SIZE_STRATEGY #endif struct MatPrimeInfo { long q; zz_pContext context; }; void InitMatPrimeInfo(MatPrimeInfo& info, long q, long w); #define NTL_MAX_MATPRIMES (20000) typedef LazyTable MatPrimeTablesType; extern MatPrimeTablesType MatPrimeTables; // a truly GLOBAL variable, shared among all threads inline long GetMatPrime(long i) { return MatPrimeTables[i]->q; } inline void RestoreMatPrime(long i) { MatPrimeTables[i]->context.restore(); } void UseMatPrime(long index); // allocates and initializes information for Mat prime #ifndef NTL_MatPrime_HALF_SIZE_STRATEGY struct MatPrime_crt_helper_scratch { ZZ t; }; struct MatPrime_crt_helper { long NumPrimes; long sz; ZZ MinusMModP; // -M mod p, M = product of primes // the following arrays are indexed 0..NumPrimes-1 // q[i] = MatPrime[i] Vec prime; // prime[i] = q[i] Vec prime_recip; // prime_recip[i] = 1/double(q[i]) Vec u; // u[i] = (M/q[i])^{-1} mod q[i] Vec uqinv; Vec ZZ_red_struct; ZZVec coeff; ZZ_ReduceStructAdapter montgomery_struct; long GetNumPrimes() const { return NumPrimes; } double cost; double GetCost() const { return cost; } }; #else struct MatPrime_crt_helper_scratch { ZZ t; }; struct MatPrime_crt_helper { long NumPrimes; long sz; ZZ MinusMModP; // -M mod p, M = product of primes // the following arrays are indexed 0..NumPrimes-1 // q[i] = MatPrime[i] Vec prime; // prime[i] = q[i] Vec prime_recip; // prime_recip[i] = 1/double(q[i]) Vec u; // u[i] = (M/q[i])^{-1} mod q[i] Vec uqinv; Vec red_struct; // Indexed 0..ceil(NumPrimes/2)-1 Vec ZZ_red_struct; // Indexed 0..ceil(NumPrimes/2)-1 ZZVec coeff; ZZ_ReduceStructAdapter montgomery_struct; long GetNumPrimes() const { return NumPrimes; } double cost; double GetCost() const { return cost; } }; #endif void build(MatPrime_crt_helper& H, const ZZ& P); void init_scratch(const MatPrime_crt_helper& H, MatPrime_crt_helper_scratch& scratch); void reduce(const MatPrime_crt_helper& H, const ZZ& value, MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch); void reconstruct(const MatPrime_crt_helper& H, ZZ& value, const MatPrime_residue_t *remainders, MatPrime_crt_helper_scratch& scratch); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/PD.h0000644417616742025610000003651314064716022016721 0ustar gid-shoupvpug-gid-shoupv#ifndef NTL_PD__H #define NTL_PD__H #include #include NTL_OPEN_NNS template struct PD { private: PD(); }; // FIXME: should distinguish more carefully: // AVX512DQ for long/double conversions // AVX512VL for certain ops applied to shorter types: // long/double conversions and mask ops // may need to translate long/double conversions for non-AVXDQ512 //=================== PD<8> implementation =============== #ifdef NTL_HAVE_AVX512F template<> struct PD<8> { __m512d data; enum { size = 8}; PD() { } PD(double x) : data(_mm512_set1_pd(x)) { } PD(__m512d _data) : data(_data) { } PD(double d0, double d1, double d2, double d3, double d4, double d5, double d6, double d7) : data(_mm512_set_pd(d7, d6, d5, d4, d3, d2, d1, d0)) { } static PD load(const double *p) { return _mm512_load_pd(p); } // load from unaligned address static PD loadu(const double *p) { return _mm512_loadu_pd(p); } }; inline void load(PD<8>& x, const double *p) { x = PD<8>::load(p); } // load from unaligned address inline void loadu(PD<8>& x, const double *p) { x = PD<8>::loadu(p); } inline void store(double *p, PD<8> a) { _mm512_store_pd(p, a.data); } // store to unaligned address inline void storeu(double *p, PD<8> a) { _mm512_storeu_pd(p, a.data); } // load and convert inline void load(PD<8>& x, const long *p) { __m512i a = _mm512_load_epi64(p); x = _mm512_cvtepi64_pd(a); } // load unaligned and convert inline void loadu(PD<8>& x, const long *p) { __m512i a = _mm512_loadu_si512(p); x = _mm512_cvtepi64_pd(a); } // convert and store inline void store(long *p, PD<8> a) { __m512i b = _mm512_cvtpd_epi64(a.data); _mm512_store_epi64(p, b); } // convert and store unaligned inline void storeu(long *p, PD<8> a) { __m512i b = _mm512_cvtpd_epi64(a.data); _mm512_storeu_si512(p, b); } // swap even/odd slots // e.g., 01234567 -> 10325476 inline PD<8> swap2(PD<8> a) { return _mm512_permute_pd(a.data, 0x55); } // swap even/odd slot-pairs // e.g., 01234567 -> 23016745 inline PD<8> swap4(PD<8> a) { return _mm512_permutex_pd(a.data, 0x4e); } // 01234567 -> 00224466 inline PD<8> dup2even(PD<8> a) { return _mm512_permute_pd(a.data, 0); } // 01234567 -> 11335577 inline PD<8> dup2odd(PD<8> a) { return _mm512_permute_pd(a.data, 0xff); } // 01234567 -> 01014545 inline PD<8> dup4even(PD<8> a) { return _mm512_permutex_pd(a.data, 0x44); } // 01234567 -> 23236767 inline PD<8> dup4odd(PD<8> a) { return _mm512_permutex_pd(a.data, 0xee); } // blend even/odd slots // 01234567, 89abcdef -> 092b4d6f inline PD<8> blend2(PD<8> a, PD<8> b) { return _mm512_mask_blend_pd(0xaa, a.data, b.data); } // FIXME: why isn't there an intrinsic that doesn't require a mask register? // blend even/odd slot-pairs // 01234567, 89abcdef -> 01ab45ef inline PD<8> blend4(PD<8> a, PD<8> b) { return _mm512_mask_blend_pd(0xcc, a.data, b.data); } // FIXME: why isn't there an intrinsic that doesn't require a mask register? // res[i] = a[i] < b[i] ? a[i] : a[i]-b[i] inline PD<8> correct_excess(PD<8> a, PD<8> b) { __mmask8 k = _mm512_cmp_pd_mask(a.data, b.data, _CMP_GE_OQ); return _mm512_mask_sub_pd(a.data, k, a.data, b.data); } // res[i] = a[i] >= 0 ? a[i] : a[i]+b[i] inline PD<8> correct_deficit(PD<8> a, PD<8> b) { __mmask8 k = _mm512_cmp_pd_mask(a.data, _mm512_setzero_pd(), _CMP_LT_OQ); return _mm512_mask_add_pd(a.data, k, a.data, b.data); } inline void clear(PD<8>& x) { x.data = _mm512_setzero_pd(); } inline PD<8> operator+(PD<8> a, PD<8> b) { return _mm512_add_pd(a.data, b.data); } inline PD<8> operator-(PD<8> a, PD<8> b) { return _mm512_sub_pd(a.data, b.data); } inline PD<8> operator*(PD<8> a, PD<8> b) { return _mm512_mul_pd(a.data, b.data); } inline PD<8> operator/(PD<8> a, PD<8> b) { return _mm512_div_pd(a.data, b.data); } inline PD<8>& operator+=(PD<8>& a, PD<8> b) { a = a + b; return a; } inline PD<8>& operator-=(PD<8>& a, PD<8> b) { a = a - b; return a; } inline PD<8>& operator*=(PD<8>& a, PD<8> b) { a = a * b; return a; } inline PD<8>& operator/=(PD<8>& a, PD<8> b) { a = a / b; return a; } // a*b+c (fused) inline PD<8> fused_muladd(PD<8> a, PD<8> b, PD<8> c) { return _mm512_fmadd_pd(a.data, b.data, c.data); } // a*b-c (fused) inline PD<8> fused_mulsub(PD<8> a, PD<8> b, PD<8> c) { return _mm512_fmsub_pd(a.data, b.data, c.data); } // -a*b+c (fused) inline PD<8> fused_negmuladd(PD<8> a, PD<8> b, PD<8> c) { return _mm512_fnmadd_pd(a.data, b.data, c.data); } #endif //=================== PD<4> implementation =============== #if (defined(NTL_HAVE_AVX2) && defined(NTL_HAVE_FMA)) template<> struct PD<4> { __m256d data; enum { size = 4}; PD() { } PD(double x) : data(_mm256_set1_pd(x)) { } PD(__m256d _data) : data(_data) { } PD(double d0, double d1, double d2, double d3) : data(_mm256_set_pd(d3, d2, d1, d0)) { } static PD load(const double *p) { return _mm256_load_pd(p); } // load from unaligned address static PD loadu(const double *p) { return _mm256_loadu_pd(p); } }; inline void load(PD<4>& x, const double *p) { x = PD<4>::load(p); } // load from unaligned address inline void loadu(PD<4>& x, const double *p) { x = PD<4>::loadu(p); } inline void store(double *p, PD<4> a) { _mm256_store_pd(p, a.data); } // store to unaligned address inline void storeu(double *p, PD<4> a) { _mm256_storeu_pd(p, a.data); } // The following assume all numbers are integers // in the range [0, 2^52). The idea is taken from here: // https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx // Some of the Intel intrinsics for loading and storing packed // integers from memory require casting between long* and __m256i*. // Strictly speaking, this can break strict aliasing rules, but // this is hopefully not a problem. // See discussion here: // https://stackoverflow.com/questions/24787268/how-to-implement-mm-storeu-epi64-without-aliasing-problems // load and convert inline void load(PD<4>& x, const long *p) { #ifdef NTL_HAVE_AVX512F __m256i a = _mm256_load_si256((const __m256i*)p); x = _mm256_cvtepi64_pd(a); #else __m256i a = _mm256_load_si256((const __m256i*)p); a = _mm256_or_si256(a, _mm256_castpd_si256(_mm256_set1_pd(1L << 52))); x = _mm256_sub_pd(_mm256_castsi256_pd(a), _mm256_set1_pd(1L << 52)); #endif } // load unaligned and convert inline void loadu(PD<4>& x, const long *p) { #ifdef NTL_HAVE_AVX512F __m256i a = _mm256_loadu_si256((const __m256i*)p); x = _mm256_cvtepi64_pd(a); #else __m256i a = _mm256_loadu_si256((const __m256i*)p); a = _mm256_or_si256(a, _mm256_castpd_si256(_mm256_set1_pd(1L << 52))); x = _mm256_sub_pd(_mm256_castsi256_pd(a), _mm256_set1_pd(1L << 52)); #endif } // convert and store inline void store(long *p, PD<4> a) { #ifdef NTL_HAVE_AVX512F __m256i b = _mm256_cvtpd_epi64(a.data); #ifdef __clang__ _mm256_store_si256((__m256i*)p, b); #else // clang doesn't define this...why?? _mm256_store_epi64(p, b); #endif #else __m256d x = a.data; x = _mm256_add_pd(x, _mm256_set1_pd(1L << 52)); __m256i b = _mm256_xor_si256( _mm256_castpd_si256(x), _mm256_castpd_si256(_mm256_set1_pd(1L << 52))); _mm256_store_si256((__m256i*)p, b); #endif } // convert and store unaligned inline void storeu(long *p, PD<4> a) { #ifdef NTL_HAVE_AVX512F __m256i b = _mm256_cvtpd_epi64(a.data); _mm256_storeu_si256((__m256i*)p, b); #else __m256d x = a.data; x = _mm256_add_pd(x, _mm256_set1_pd(1L << 52)); __m256i b = _mm256_xor_si256( _mm256_castpd_si256(x), _mm256_castpd_si256(_mm256_set1_pd(1L << 52))); _mm256_storeu_si256((__m256i*)p, b); #endif } // swap even/odd slots // e.g., 0123 -> 1032 inline PD<4> swap2(PD<4> a) { return _mm256_permute_pd(a.data, 0x5); } // 0123 -> 0022 inline PD<4> dup2even(PD<4> a) { return _mm256_permute_pd(a.data, 0); } // 0123 -> 1133 inline PD<4> dup2odd(PD<4> a) { return _mm256_permute_pd(a.data, 0xf); } // blend even/odd slots // 0123, 4567 -> 0527 inline PD<4> blend2(PD<4> a, PD<4> b) { return _mm256_blend_pd(a.data, b.data, 0xa); } // res[i] = a[i] < b[i] ? a[i] : a[i]-b[i] inline PD<4> correct_excess(PD<4> a, PD<4> b) { #ifdef NTL_HAVE_AVX512F __mmask8 k = _mm256_cmp_pd_mask(a.data, b.data, _CMP_GE_OQ); return _mm256_mask_sub_pd(a.data, k, a.data, b.data); #else __m256d mask = _mm256_cmp_pd(a.data, b.data, _CMP_GE_OQ); __m256d corrected = _mm256_sub_pd(a.data, b.data); return _mm256_blendv_pd(a.data, corrected, mask); #endif } // res[i] = a[i] >= 0 ? a[i] : a[i]+b[i] inline PD<4> correct_deficit(PD<4> a, PD<4> b) { #ifdef NTL_HAVE_AVX512F __mmask8 k = _mm256_cmp_pd_mask(a.data, _mm256_setzero_pd(), _CMP_LT_OQ); return _mm256_mask_add_pd(a.data, k, a.data, b.data); #else __m256d mask = _mm256_cmp_pd(a.data, _mm256_setzero_pd(), _CMP_LT_OQ); __m256d corrected = _mm256_add_pd(a.data, b.data); return _mm256_blendv_pd(a.data, corrected, mask); #endif } inline void clear(PD<4>& x) { x.data = _mm256_setzero_pd(); } inline PD<4> operator+(PD<4> a, PD<4> b) { return _mm256_add_pd(a.data, b.data); } inline PD<4> operator-(PD<4> a, PD<4> b) { return _mm256_sub_pd(a.data, b.data); } inline PD<4> operator*(PD<4> a, PD<4> b) { return _mm256_mul_pd(a.data, b.data); } inline PD<4> operator/(PD<4> a, PD<4> b) { return _mm256_div_pd(a.data, b.data); } inline PD<4>& operator+=(PD<4>& a, PD<4> b) { a = a + b; return a; } inline PD<4>& operator-=(PD<4>& a, PD<4> b) { a = a - b; return a; } inline PD<4>& operator*=(PD<4>& a, PD<4> b) { a = a * b; return a; } inline PD<4>& operator/=(PD<4>& a, PD<4> b) { a = a / b; return a; } // a*b+c (fused) inline PD<4> fused_muladd(PD<4> a, PD<4> b, PD<4> c) { return _mm256_fmadd_pd(a.data, b.data, c.data); } // a*b-c (fused) inline PD<4> fused_mulsub(PD<4> a, PD<4> b, PD<4> c) { return _mm256_fmsub_pd(a.data, b.data, c.data); } // -a*b+c (fused) inline PD<4> fused_negmuladd(PD<4> a, PD<4> b, PD<4> c) { return _mm256_fnmadd_pd(a.data, b.data, c.data); } //=================== PD<2> implementation =============== template<> struct PD<2> { __m128d data; enum { size = 2}; PD() { } PD(double x) : data(_mm_set1_pd(x)) { } PD(__m128d _data) : data(_data) { } PD(double d0, double d1) : data(_mm_set_pd(d1, d0)) { } static PD load(const double *p) { return _mm_load_pd(p); } // load from unaligned address static PD loadu(const double *p) { return _mm_loadu_pd(p); } }; inline void load(PD<2>& x, const double *p) { x = PD<2>::load(p); } // load from unaligned address inline void loadu(PD<2>& x, const double *p) { x = PD<2>::loadu(p); } inline void store(double *p, PD<2> a) { _mm_store_pd(p, a.data); } // store to unaligned address inline void storeu(double *p, PD<2> a) { _mm_storeu_pd(p, a.data); } // The following assume all numbers are integers // in the range [0, 2^52). The idea is taken from here: // https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx // load and convert inline void load(PD<2>& x, const long *p) { #ifdef NTL_HAVE_AVX512F __m128i a = _mm_load_si128((const __m128i*)p); x = _mm_cvtepi64_pd(a); #else __m128i a = _mm_load_si128((const __m128i*)p); a = _mm_or_si128(a, _mm_castpd_si128(_mm_set1_pd(1L << 52))); x = _mm_sub_pd(_mm_castsi128_pd(a), _mm_set1_pd(1L << 52)); #endif } // load unaligned and convert inline void loadu(PD<2>& x, const long *p) { #ifdef NTL_HAVE_AVX512F __m128i a = _mm_loadu_si128((const __m128i*)p); x = _mm_cvtepi64_pd(a); #else __m128i a = _mm_loadu_si128((const __m128i*)p); a = _mm_or_si128(a, _mm_castpd_si128(_mm_set1_pd(1L << 52))); x = _mm_sub_pd(_mm_castsi128_pd(a), _mm_set1_pd(1L << 52)); #endif } // convert and store inline void store(long *p, PD<2> a) { #ifdef NTL_HAVE_AVX512F __m128i b = _mm_cvtpd_epi64(a.data); #ifdef __clang__ _mm_store_si128((__m128i*)p, b); #else // clang doesn't define this...why?? _mm_store_epi64(p, b); #endif #else __m128d x = a.data; x = _mm_add_pd(x, _mm_set1_pd(1L << 52)); __m128i b = _mm_xor_si128( _mm_castpd_si128(x), _mm_castpd_si128(_mm_set1_pd(1L << 52))); _mm_store_si128((__m128i*)p, b); #endif } // convert and store unaligned inline void storeu(long *p, PD<2> a) { #ifdef NTL_HAVE_AVX512F __m128i b = _mm_cvtpd_epi64(a.data); _mm_storeu_si128((__m128i*)p, b); #else __m128d x = a.data; x = _mm_add_pd(x, _mm_set1_pd(1L << 52)); __m128i b = _mm_xor_si128( _mm_castpd_si128(x), _mm_castpd_si128(_mm_set1_pd(1L << 52))); _mm_storeu_si128((__m128i*)p, b); #endif } // res[i] = a[i] < b[i] ? a[i] : a[i]-b[i] inline PD<2> correct_excess(PD<2> a, PD<2> b) { #ifdef NTL_HAVE_AVX512F __mmask8 k = _mm_cmp_pd_mask(a.data, b.data, _CMP_GE_OQ); return _mm_mask_sub_pd(a.data, k, a.data, b.data); #else __m128d mask = _mm_cmp_pd(a.data, b.data, _CMP_GE_OQ); __m128d corrected = _mm_sub_pd(a.data, b.data); return _mm_blendv_pd(a.data, corrected, mask); #endif } // res[i] = a[i] >= 0 ? a[i] : a[i]+b[i] inline PD<2> correct_deficit(PD<2> a, PD<2> b) { #ifdef NTL_HAVE_AVX512F __mmask8 k = _mm_cmp_pd_mask(a.data, _mm_setzero_pd(), _CMP_LT_OQ); return _mm_mask_add_pd(a.data, k, a.data, b.data); #else __m128d mask = _mm_cmp_pd(a.data, _mm_setzero_pd(), _CMP_LT_OQ); __m128d corrected = _mm_add_pd(a.data, b.data); return _mm_blendv_pd(a.data, corrected, mask); #endif } inline void clear(PD<2>& x) { x.data = _mm_setzero_pd(); } inline PD<2> operator+(PD<2> a, PD<2> b) { return _mm_add_pd(a.data, b.data); } inline PD<2> operator-(PD<2> a, PD<2> b) { return _mm_sub_pd(a.data, b.data); } inline PD<2> operator*(PD<2> a, PD<2> b) { return _mm_mul_pd(a.data, b.data); } inline PD<2> operator/(PD<2> a, PD<2> b) { return _mm_div_pd(a.data, b.data); } inline PD<2>& operator+=(PD<2>& a, PD<2> b) { a = a + b; return a; } inline PD<2>& operator-=(PD<2>& a, PD<2> b) { a = a - b; return a; } inline PD<2>& operator*=(PD<2>& a, PD<2> b) { a = a * b; return a; } inline PD<2>& operator/=(PD<2>& a, PD<2> b) { a = a / b; return a; } // a*b+c (fused) inline PD<2> fused_muladd(PD<2> a, PD<2> b, PD<2> c) { return _mm_fmadd_pd(a.data, b.data, c.data); } // a*b-c (fused) inline PD<2> fused_mulsub(PD<2> a, PD<2> b, PD<2> c) { return _mm_fmsub_pd(a.data, b.data, c.data); } // -a*b+c (fused) inline PD<2> fused_negmuladd(PD<2> a, PD<2> b, PD<2> c) { return _mm_fnmadd_pd(a.data, b.data, c.data); } //================== PD<8>/PD<4> conversions ================ #ifdef NTL_HAVE_AVX512F // 0123, 4567 -> 01234567 inline PD<8> join(PD<4> a, PD<4> b) { __m512d c = _mm512_castpd256_pd512(a.data); return _mm512_insertf64x4(c, b.data, 1); } // 01234567 -> 0123 inline PD<4> get_lo(PD<8> a) { return _mm512_extractf64x4_pd(a.data, 0); } // 01234567 -> 4567 inline PD<4> get_hi(PD<8> a) { return _mm512_extractf64x4_pd(a.data, 1); } #endif //================== PD<4>/PD<2> conversions ================ // 01, 23 -> 0123 inline PD<4> join(PD<2> a, PD<2> b) #if 0 // some versions of gcc are buggy and don't define this function { return _mm256_set_m128d(b.data, a.data); } #else { return _mm256_insertf128_pd(_mm256_castpd128_pd256(a.data), b.data, 1); } #endif // 0123 -> 01 inline PD<2> get_lo(PD<4> a) { return _mm256_extractf128_pd(a.data, 0); } // 0123 -> 23 inline PD<2> get_hi(PD<4> a) { return _mm256_extractf128_pd(a.data, 1); } #endif NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/pd_FFT.h0000644417616742025610000000201214064716022017503 0ustar gid-shoupvpug-gid-shoupv #ifndef NTL_pd_FFT__H #define NTL_pd_FFT__H #include NTL_OPEN_NNS // Sets control register so that rounding mode // is "down". Destructor restores control regsiter. struct CSRPush { unsigned int reg; CSRPush(); ~CSRPush(); }; struct pd_mod_t { double q; const double **wtab; const double **wqinvtab; const double **wtab1; const double **wqinvtab1; }; void pd_LazyPrepMulModPrecon_impl(double *bninv, const double *b, double n, long len); void pd_fft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, long xn); void pd_fft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, long xn, double fac); void pd_ifft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn); void pd_ifft_trunc_impl(long* A, const long* a, double* xp, long lgN, const pd_mod_t& mod, long yn, double fac); NTL_CLOSE_NNS #endif ntl-11.5.1/include/NTL/linux_s390x.h0000644417616742025610000000410614064716022020514 0ustar gid-shoupvpug-gid-shoupv#ifndef LINUX_S390X_H #define LINUX_S390X_H #if defined(__s390x__) && defined(__linux__) \ && (defined(__GNUC__) || defined(__clang__)) #define LINUX_S390X #include /* message-security-assist extension 8 */ #define MSA8 146 /* Map a facility bit number or function code to its bit mask. */ #define MASK64(n) \ (1ULL << (63 - (n) % 64)) /* Map a facility bit number or function code to its offset. */ #define OFF64(n) (n / 64) /* Function codes */ #define CPACF_KMA_QUERY 0 #define CPACF_KMA_GCM_AES_256 20 /* Function code flags */ #define CPACF_KMA_LAAD 0x200 /* Last-AAD */ #define CPACF_KMA_HS 0x400 /* Hash-subkey Supplied */ static inline unsigned long stfle(unsigned long flist[], unsigned long nmemb) { register unsigned long r0 __asm__("0") = (unsigned long)nmemb - 1; __asm__ volatile( ".insn s,%[opc]<<16,0(%[flist])" : "+d" (r0) : [flist] "a" (flist), [opc] "i" (0xb2b0) : "memory", "cc" ); return r0 + 1; } /* KMA (cipher message with authentication) */ static inline void cpacf_kma(unsigned long fc, void *param, unsigned char *out, const unsigned char *aad, unsigned long aadlen, const unsigned char *in, unsigned long inlen) { register unsigned long r0 __asm__("0") = (unsigned long)fc; register unsigned long r1 __asm__("1") = (unsigned long)param; register unsigned long r2 __asm__("2") = (unsigned long)in; register unsigned long r3 __asm__("3") = (unsigned long)inlen; register unsigned long r4 __asm__("4") = (unsigned long)aad; register unsigned long r5 __asm__("5") = (unsigned long)aadlen; register unsigned long r6 __asm__("6") = (unsigned long)out; __asm__ volatile( "0: .insn rrf,%[opc]<<16,%[out],%[in],%[aad],0\n" " brc 1,0b\n" /* partial completion */ : [out] "+a" (r6), [in] "+a" (r2), [inlen] "+d" (r3), [aad] "+a" (r4), [aadlen] "+d" (r5) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb929) : "cc", "memory" ); } #endif #endif ntl-11.5.1/include/NTL/PackageInfo.h0000644417616742025610000000003014064716022020546 0ustar gid-shoupvpug-gid-shoupv#define NTL_PACKAGE (1) ntl-11.5.1/include/NTL/ALL_FEATURES.h0000644417616742025610000000075614064716023020325 0ustar gid-shoupvpug-gid-shoupv #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ntl-11.5.1/include/NTL/REPORT_ALL_FEATURES.h0000644417616742025610000000217114064716023021411 0ustar gid-shoupvpug-gid-shoupv #ifdef NTL_HAVE_ALIGNED_ARRAY std::cerr << "NTL_HAVE_ALIGNED_ARRAY\n"; #endif #ifdef NTL_HAVE_BUILTIN_CLZL std::cerr << "NTL_HAVE_BUILTIN_CLZL\n"; #endif #ifdef NTL_HAVE_LL_TYPE std::cerr << "NTL_HAVE_LL_TYPE\n"; #endif #ifdef NTL_HAVE_SSSE3 std::cerr << "NTL_HAVE_SSSE3\n"; #endif #ifdef NTL_HAVE_AVX std::cerr << "NTL_HAVE_AVX\n"; #endif #ifdef NTL_HAVE_PCLMUL std::cerr << "NTL_HAVE_PCLMUL\n"; #endif #ifdef NTL_HAVE_AVX2 std::cerr << "NTL_HAVE_AVX2\n"; #endif #ifdef NTL_HAVE_FMA std::cerr << "NTL_HAVE_FMA\n"; #endif #ifdef NTL_HAVE_AVX512F std::cerr << "NTL_HAVE_AVX512F\n"; #endif #ifdef NTL_HAVE_COPY_TRAITS1 std::cerr << "NTL_HAVE_COPY_TRAITS1\n"; #endif #ifdef NTL_HAVE_COPY_TRAITS2 std::cerr << "NTL_HAVE_COPY_TRAITS2\n"; #endif #ifdef NTL_HAVE_CHRONO_TIME std::cerr << "NTL_HAVE_CHRONO_TIME\n"; #endif #ifdef NTL_HAVE_MACOS_TIME std::cerr << "NTL_HAVE_MACOS_TIME\n"; #endif #ifdef NTL_HAVE_POSIX_TIME std::cerr << "NTL_HAVE_POSIX_TIME\n"; #endif #ifdef NTL_HAVE_AES_NI std::cerr << "NTL_HAVE_AES_NI\n"; #endif #ifdef NTL_HAVE_KMA std::cerr << "NTL_HAVE_KMA\n"; #endif ntl-11.5.1/include/NTL/HAVE_ALIGNED_ARRAY.h0000644417616742025610000000000114064716023021202 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_BUILTIN_CLZL.h0000644417616742025610000000000114064716023021133 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_LL_TYPE.h0000644417616742025610000000000114064716023020351 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_SSSE3.h0000644417616742025610000000000114064716023020041 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_AVX.h0000644417616742025610000000000114064716023017637 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_PCLMUL.h0000644417616742025610000000000114064716023020175 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_AVX2.h0000644417616742025610000000000114064716023017721 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_FMA.h0000644417616742025610000000000114064716023017604 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_AVX512F.h0000644417616742025610000000000114064716023020175 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_COPY_TRAITS1.h0000644417616742025610000000000114064716023021122 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_COPY_TRAITS2.h0000644417616742025610000000000114064716023021123 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_CHRONO_TIME.h0000644417616742025610000000000114064716023021007 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_MACOS_TIME.h0000644417616742025610000000000114064716023020661 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_POSIX_TIME.h0000644417616742025610000000000114064716023020721 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_AES_NI.h0000644417616742025610000000000114064716023020177 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/include/NTL/HAVE_KMA.h0000644417616742025610000000000114064716023017611 0ustar gid-shoupvpug-gid-shoupv ntl-11.5.1/doc/0000755417616742025610000000000014064716023014723 5ustar gid-shoupvpug-gid-shoupvntl-11.5.1/doc/copying.txt0000644417616742025610000006653414064716022017151 0ustar gid-shoupvpug-gid-shoupv COPYRIGHT NOTICE NTL -- A Library for Doing Number Theory Copyright (C) 1996-2021 Victor Shoup The most recent version of NTL is available at http://www.shoup.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA This entire copyright notice should be placed in an appropriately conspicuous place accompanying all distributions of software that make use of NTL. The above terms apply to all of the software modules distributed with NTL, i.e., all source files in either the ntl-xxx.tar.gz or WinNTL-xxx.zip distributions. In general, the individual files do not contain copyright notices. Note that the traditional (non-GMP) long integer code used by NTL is derived from---and represents an almost complete rewrite of---a package originally developed and copyrighted by Arjen Lenstra, who has agreed to renounce any copyright claims on the particular version of the long integer package appearing in NTL, so that this package now is covered by LGPLv2.1+ as well. Note that NTL can be optionally built using GMP (see http://gmplib.org). This is currently the default behavior in the Unix distribution of NTL (i.e., ntl-XXX.tar.gz). GMP is licensed under the terms of the LGPL. The most recent versions of GMP use version 3 of the LGPL, while some older versions use version 2.1 of the LGPL. It is possible to use some of these older versions with NTL. While NTL is fully functional without GMP, it may be significantly slower. Note that one can optionally build NTL with the gf2x package (see http://gforge.inria.fr/projects/gf2x/). However, the current version of gf2x is licensed on the GPL, which is more restrictive than the LGPL. The authors of gf2x have indicated that an LGPL version of their package may be released at some point in the future. In any case, NTL can be used and is fully functional without the gf2x package. Note that the quad_float module in NTL is derived from the doubledouble package, originally developed by Keith Briggs (see http://keithbriggs.info/doubledouble.html), and also licensed under LGPLv2.1+. The files quad_float.cpp and quad_float.h contain more detailed copyright notices. Note that the file mat_lzz_p.cpp contains an implemention of Strassen's matrix multiplication algorithm which is derived from the implementation in FLINT. The latter is copyrighted by Martin Albrecht, William Hart, and Fredrik Johansson, and also licensed under LGPLv2.1+. See file mat_lzz_p.cpp for a more detailed notice. Note that the the file ZZ.cpp contains an implementation of SHA256 which is derived from work by Brad Conte, which is in the public domain. See file ZZ.cpp for a more detailed notice. END COPYRIGHT NOTICE Following is the complete text of the GNU General Lesser Public License, version 2.1. Note that the copyright notice below applies to the text of the license itself, and not to NTL. GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ntl-11.5.1/doc/BasicThreadPool.txt0000644417616742025610000004215514064716022020475 0ustar gid-shoupvpug-gid-shoupv /************************************************************************ MODULE: BasicThreadPool SUMMARY: A simple thread pool class BasicThreadPool, as well as some higher-level macros which facilitite simple parallel for loops. ***************************************************************************/ // ********************** Simple parallel for loops ************************** // // We begin with a description of the higher-level macros for writing simple // parallel for loops. These facilitaties are activated only when NTL is // configured with NTL_THREAD_BOOST=on (which implies NTL_THREADS=on). // However, code that uses these facilties should still compile and run // correctly even when NTL_THREAD_BOOST=off, or even when NTL_THREADS=off, so // this is the simplest way to write parallel for loops across a range of // compile-time and run-time environments. Note that if NTL_THREADS=on, C++11 // features are reqired, but when NTL_THREADS=off, these features are not // required, so the code should compile on older C++ compilers. // // Here is a simple recipe for writing parallel for loop. // // At the start of program execution, your program should execute SetNumThreads(nt); // You can choose nt to be any positive integer, but for best results, it // should correspond to the number of available cores on your machine. // [NOTE: if NTL_THREAD_BOOST=off, this function is still defined, but does // nothing.] // // Now consider the following routine: void mul(ZZ *x, const ZZ *a, const ZZ *b, long n) { for (long i = 0; i < n; i++) mul(x[i], a[i], b[i]); } // We can parallelize it as follows: void mul(ZZ *x, const ZZ *a, const ZZ *b, long n) { NTL_EXEC_RANGE(n, first, last) for (long i = first; i < last; i++) mul(x[i], a[i], b[i]); NTL_EXEC_RANGE_END } // NTL_EXEC_RANGE and NTL_EXEC_RANGE_END are macros that just "do the right // thing". If there are nt threads available, the interval [0..n) will be // partitioned into (up to) nt subintervals, and a different thread will be // used to process each subinterval. You still have to write the for loop // yourself: the macro just declares and initializes variables "first" and // "last" (or whatever you want to call them) of type long that represent the // subinterval [first..last) to be processed by one thread. // // Note that the current thread participates as one of the nt available // threads, and that the current thread will wait for all other participating threads // to finish their task before proceeding. The current thread can be identified // as the one with first == 0. // // Withing the "body" of this construct, you can freely reference any variables // that are visible at this point. This is implemented using the C++ lambda // feature (capturing all variables by reference). // // This construct will still work even if threads are disabled, in which case // it runs single-threaded with first=0 and last=n. // // Note that the code within the EXEC_RANGE body could call other routines that // themselves attempt to execute an EXEC_RANGE: if this happens, the latter // EXEC_RANGE will detect this and run single-threaded. // // You may wish to do other things within the EXEC_RANGE body than just execute // a loop. One thing you may want to do is to declare variables. Another // thing you may want to do is setup a local context for a ZZ_p modulus (or // other type of modulus). Here is an example of doing this: void mul(ZZ_p *x, const ZZ_p *a, const ZZ_p *b, long n) { ZZ_pContext context; context.save(); NTL_EXEC_RANGE(n, first, last) context.restore(); for (long i = first; i < last; i++) mul(x[i], a[i], b[i]); NTL_EXEC_RANGE_END } // Another useful function is AvailableThreads(), which will return the number // of available threads. If threads or thread boosting is not enabled, this // will return 1. Even if thread boosting is enabled, this may return 1 if for // whatever reason, the thread pool is not available for use (for example, // SetNumThreads was never called, or the thread pool is already active). // // A lower-level set of tools is available, which allow you to simply run a // specified number of threads. Assuming nt <= AvailableThreads(), the code NTL_EXEC_INDEX(nt, index) ... code ... NTL_EXEC_INDEX_END // will execute the body on nt different threads, each with a unique index in // the range [0..nt). A variable named "index" (or whatever name you specify) // of type long will hold the given index. Just as with EXEC_RANGE, the current // thread will participate as one of the nt threads, and will always be // assigned an index of 0. // // This tool is useful if you need to manage memory a bit more carefully. For // example, the following code will compute an inner product using all // available threads: ZZ InnerProd(const ZZ *a, const ZZ *b, long n) { PartitionInfo pinfo(n); long cnt = pinfo.NumIntervals(); Vec acc; acc.SetLength(cnt); NTL_EXEC_INDEX(cnt, index) long first, last; pinfo.interval(first, last, index); ZZ& sum = acc[index]; sum = 0; for (long i = first; i < last; i++) MulAddTo(sum, a[i], b[i]); NTL_EXEC_INDEX_END ZZ sum; sum = 0; for (long i = 0; i < cnt; i++) sum += acc[i]; return sum; } // This example also illustrates the class PartitionInfo, which is useful for // partitioning a large interval into smaller intervals (it is used internally // by EXEC_RANGE). The constructor takes a single argument (in this example n) // and computes a partition of [0..n) into nearly equally sized subintervals. // The method NumIntervals() returns the number of subintervals, and the method // interval(first, last, index) sets first and last according to the endpoints // of the subinterval [first..last) with the given index. // // So in this example, cnt threads will run, each accumulating a sum into a // corresponding element of the vector acc, and afterwords, these elements are // summed. // // Note that if threads are not enabled or otherwise unavailable, the above // code will compile and run correctly (just using one thread). // // Finally, there is a "guarded" version of NTL_EXEC_RANGE called // NTL_GEXEC_RANGE. This allows one to dynamically "guard" against parallel // execution. For example, on very small problems the runtime overhead of a // parallel for loop may not be worthwhile, or in other situations parallel // execution could cause incorrect behavior. See below for details. // ********************** Other useful patterns ************************* // // You can use these tools together with some other elements of the // C++11 standard library to implement some other useful patterns. // // ****** Accumulation: // // Consider again the example above of computing an inner product. // This can be implemented more easily as follows: ZZ InnerProd(const ZZ *a, const ZZ *b, long n) { ZZ sum; sum = 0; std::mutex sum_mutex; NTL_EXEC_RANGE(n, first, last) ZZ acc; acc = 0; for (long i = first; i < last; i++) MulAddTo(acc, a[i], b[i]); std::lock_guard guard(sum_mutex); sum += acc; NTL_EXEC_RANGE_END return sum; } // There is some extra run-time overead, but in many cases this is negligible. // Also, unlike the code above for computing an inner product, this code will // require C++11. // ****** dynamic scheduling // // Suppose you need to perform parallel tasks i = 0..n-1, but the tasks may // vary greatly in their run time. A more efficient approach than a simple // NTL_EXEC_RANGE is as follows: long nt = AvailableThreads(); std::atomic counter(n); NTL_EXEC_INDEX(nt, index) long i; while ((i = --counter) >= 0) { // perform task i ... } NTL_EXEC_INDEX_END // Each time the body of the loop is executed, a different task i = 0..n-1 is // performed. // ********************** Simple parallel divide and conquer ************ // // Some tools are provided for parallelizing simple divide and conquer // algorithms. The interface for this set of tools is still experimental // and subject to change (but hopefully not). // // Suppose you have a recursive divide and conquer algorithm: void rec_alg(...) { ... // two recursive invocations that can run in parallel rec_alg(...call 0...); rec_alg(...call 1...); ... } // and this algorithm is invoked initially as void alg(...) { rec_alg(...initial call...); } // Then the following recipe will paralelize it: void rec_alg(..., RecursiveThreadPool *pool) { ... NTL_EXEC_DIVIDE(seq, pool, helper, load, rec_alg(...call 0..., helper.subpool(0)), rec_alg(...call 1..., helper.subpool(1)) ) ... } void alg(...) { rec_alg(...initial call..., NTL_INIT_DIVIDE); } // Here, seq is a boolean "guard" value: if true, the two recursive calls will // run sequentially, as usual. Also, load is a floating point number, which // represents the fraction of threads that should be assigned to call 0. // If the load should be equally balanced, then load=0.5 is a good choice. // The name helper is the name of an auxilliary object, which will be in the // scope of the two recursive calls. It supplies a method helper.concurrent(), // which returns true if the two calls are being run concurrently, and false // otherwise. // If thread-boosting is not enabled, these macros will revert to the normal // sequential execution, with no overhead. If thread-boosting is enabled, then // the two calls may or may not run concurrently, depending on a number of // factors. If they do run concurrently, call 0 will run on the current // thread, while call 1 will run on another thread; in addition, when the // current thread finishes execution of call 0, it will wait for the execution // of call 1 on the other thread to finish before continuing any further. // As one can see, the use cases here are fairly limited to those in which you // have a recursive algorithm that calls itself exactly twice. One example of // this is QuickSort. Another example is a recursive FFT. // ************************** Thread Pools ****************************** // // The above facilities are built on top of a more general thread pool class, // which you may use for your own purposes. // // You create a thread pool by constructing a BasicThreadPool object. For // example: long nthreads = 4; BasicThreadPool pool(nthreads); // creates a thread pool of 4 threads. These threads will exist until the // destructor for pool is called. // // The simplest way to use a thread pools is as follows. Suppose you have a // task that consists of sz subtasks, indexed 0..sz-1. Then you can write: pool.exec_range(sz, [&](long first, long last) { for (long i = first; i < last; i++) { ... code to process subtask i ... } } ); // The second argument to exec_range is a C++11 "lambda". The "[&]" indicates // that all local variables in the calling context are captured by reference, // so the lambda body can reference all visible local variables directly. // C++11 provides other methods for capturing local variables. The interval // [0..sz) is partitioned into subintervals of the form [first..last), which // are processed by the code in the supplied lambda. // // A lower-level interface is also provided. One can write: pool.exec_index(cnt, [&](long index) { ... code to process index i ... } ); // This will activate exactly cnt threads with indices 0..cnt-1, and execute // the given code on each index. The parameter cnt must not exceed nthreads, // otherwise an error is raised. // ==================================================================== // // NOTES: // // When one activates a thread pool with nthreads threads, the *current* thread // (the one activating the pool) will also participate in the computation. // This means that the thread pool only contains nthreads-1 other threads. // // If, during an activation, any thread throws an exception, it will be caught // and rethrown in the activating thread when all the threads complete. If // more than one thread throws an exception, the first one that is caught is // the one that is rethrown. // // Methods are also provided for adding, deleting, and moving threads in and // among thread pools. // // If NTL_THREADS=off, the corresponding header file may be included, but the // BasicThreadPool class is not defined. // // Unlike most classes in NTL, the BasicThreadPool is not relocatable and hence // cannot be used in a Vec. One should first wrap it in a pointer class, such // as UniquePtr. // class BasicThreadPool: provided basic functionality for thread pools class BasicThreadPool { private: BasicThreadPool(const BasicThreadPool&); // disabled void operator=(const BasicThreadPool&); // disabled public: explicit BasicThreadPool(long nthreads); // creates a pool with nthreads threads, including the current thread // (so nthreads-1 other threads get created) template void exec_range(long sz, const Fct& fct); // activate by range (see example usage above) template void exec_index(long cnt, const Fct& fct); // activate by index (see example usage above) void add(long n = 1); // add n threads to the pool long NumThreads() const; // return number of threads (including current thread) void remove(long n = 1); // remove n threads from the pool void move(BasicThreadPool& other, long n = 1) // move n threads from other pool to this pool bool active() const; // indicates an activation is in process: invoking any of the methods // exec_index, exec_range, add, remove, move, or the destructor // whie active will raise an error template static void relaxed_exec_range(BasicThreadPool *pool, long sz, const Fct& fct); // similar to pool->exec_range(sz, fct), but will still work even // if !pool or pool->active(), using just the current thread template static void relaxed_exec_index(BasicThreadPool *pool, long cnt, const Fct& fct); // similar to pool->exec_index(cnt, fct), but will still work even // if !pool or pool->active(), provided cnt <= 1, using just the current thread }; // THREAD BOOSTING FEATURES: void SetNumThreads(long nt); // convenience routine to set NTL's thread pool. // If called more than once, the old thread pool is destroyed and // replaced by a new one. // If NTL_THREAD_BOOST=off, then this is still defined, but does nothing. long AvailableThreads(); // Number of threads currently availble to use in NTL's thread pool. This is // always at least 1 (for the current thread). // If NTL_THREAD_BOOST=off, then this is still defined, and always returns 1. BasicThreadPool *GetThreadPool(); void ResetThreadPool(BasicThreadPool *pool = 0); BasicThreadPool *ReleaseThreadPool(); // Routines to get and set NTL's thread pool. The interfaces parallel NTL's // UniquePtr class, and indeed, behind the scenes, NTL's thread pool is stored // as a UniquePtr. // These are only declared when NTL_THREAD_BOOST=on. #define NTL_EXEC_RANGE(sz, first, last) ... #define NTL_EXEC_RANGE_END ... #define NTL_EXEC_INDEX(cnt, index) ... #define NTL_EXEC_INDEX_END ... // convenience macros to implement "parallel for loops" using NTL's thread // pool. See examples above for usage. If NTL_THREAD_BOOST=off, then these // are still defined, and code will run on a single thread #define NTL_GEXEC_RANGE(seq, sz, first, last) ... #define NTL_GEXEC_RANGE_END ... // "guarded" version of NTL_EXEC_RANGE: if seq evaluates to true, the code runs // on a single thread. This is useful in avoiding situations where the // overhead of a parallel loop is too high. If seq evaluates to the constant // true, a good compiler will optimize code to run on a single thread, with no // overhead. #define NTL_IMPORT(x) // To be used in conjunction with NTL_EXEC_RANGE and friends. When // NTL_THREAD_BOOST=on, this will copy the variable named x from the enclosing // scope to a local copy. This should only be used for types with cheap // copies, such as scalars and pointers. In some situations, this allows the // compiler to optimize a bit more aggressively. One or more of these may be // placed right after an NTL_EXEC_RANGE. // When NTL_THREAD_BOOST=off, this is still defined, and does nothing. // class PartitionInfo: A helper class to facilitate partitioning an interval // into subintervals. NOTE: this class is available, even when // NTL_THREAD_BOOST=off. class PartitionInfo { public: explicit PartitionInfo(long sz, long nt = AvailableThreads()); // partitions [0..sz) into at most nt subintervals. sz may be 0 or // negative, in which case the number of subintervals is 0. long NumIntervals() const; // return the number of subintervals void interval(long& first, long& last, long i) const; // [first..last) is the ith interval, where i in [0..NumInvervals()). No // range checking is performed. }; ntl-11.5.1/doc/GF2.txt0000644417616742025610000001371614064716022016051 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2 SUMMARY: The class GF2 represents the field GF(2). Computationally speaking, it is not a particularly useful class. Its main use is to make the interfaces to the various finite field classes as uniform as possible. The header file for GF2 also declares the class ref_GF2, which use used to represent non-const references to GF2's, such as those obtained from indexing a vec_GF2, which "packs" GF2's into words. There are implicit conversions from ref_GF2 to const GF2 and from GF2& to ref_GF2. Therefore, if you want to declare a function that takes a non-const reference to a GF2, you should declare the parameter of type ref_GF2: this will allow you to pass variables of type GF2 as well as elements of vec_GF2's obtained through indexing. For all functions defined below which take a parameter of type GF2&, there is also a function that takes a parameter of type ref_GF2. Theoretically, we could have just defined the functions that take the ref_GF2 parameter type, because of the implicit conversion from GF2& to ref_GF2; however, for efficiency reasons, both flavors are actually provided. It is recommended that higher-level functions use the ref_GF2 type exclusively. \**************************************************************************/ #include #include class GF2 { public: GF2(); // initial value 0 GF2(const GF2& a); // copy constructor explicit GF2(long a); // promotion constructor GF2& operator=(const GF2& a); // assignment GF2& operator=(long a); // assignment // typedefs to aid in generic programming typedef long rep_type; typedef GF2Context context_type; typedef GF2Bak bak_type; typedef GF2Push push_type; typedef GF2X poly_type; }; long rep(GF2 a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(GF2 a, GF2 b); long operator!=(GF2 a, GF2 b); long IsZero(GF2 a); // test for 0 long IsOne(GF2 a); // test for 1 // PROMOTIONS: operators ==, != promote long to GF2 on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2 operator+(GF2 a, GF2 b); GF2 operator-(GF2 a, GF2 b); GF2 operator-(GF2 a); // unary - GF2& operator+=(GF2& x, GF2 a); GF2& operator+=(GF2& x, long a); GF2& operator-=(GF2& x, GF2 a); GF2& operator-=(GF2& x, long a); GF2& operator++(GF2& x); // prefix void operator++(GF2& x, int); // postfix GF2& operator--(GF2& x); // prefix void operator--(GF2& x, int); // postfix // procedural versions: void add(GF2& x, GF2 a, GF2 b); // x = a + b void sub(GF2& x, GF2 a, GF2 b); // x = a - b void negate(GF2& x, GF2 a); // x = -a // PROMOTIONS: binary +, -, and procedures add, sub promote // from long to GF2 on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2 operator*(GF2 a, GF2 b); GF2& operator*=(GF2& x, GF2 a); GF2& operator*=(GF2& x, long a); // procedural versions: void mul(GF2& x, GF2 a, GF2 b); // x = a * b void sqr(GF2& x, GF2 a); // x = a^2 GF2 sqr(GF2 a); // PROMOTIONS: operator * and procedure mul promote from long to GF2 // on (a, b). /**************************************************************************\ Division \**************************************************************************/ operator notation: GF2 operator/(z_p a, GF2 b); GF2& operator/=(GF2& x, GF2 a); GF2& operator/=(GF2& x, long a); procedural versions: void div(GF2& x, GF2 a, GF2 b); // x = a/b void inv(GF2& x, GF2 a); GF2 inv(GF2 a); // x = 1/a // PROMOTIONS: operator / and procedure div promote from long to GF2 // on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(GF2& x, GF2 a, long e); // x = a^e (e may be negative) GF2 power(GF2 a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(GF2& x); GF2 random_GF2(); // x = random element in GF2. Uses RandomBnd from ZZ. /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, GF2 a); istream& operator>>(istream& s, GF2& x); // a ZZ is read and reduced mod 2 /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2& x); // x = 0 void set(GF2& x); // x = 1 void GF2::swap(GF2& x); void swap(GF2& x, GF2& y); // swap static GF2 GF2::zero(); // GF2::zero() yields a read-only reference to zero static long GF2::modulus(); // GF2::modulus() returns the value 2 template<> class Vec; // Forward declaration of the explicit specialization // of Vec. This specialization is defined in , // which must be included in source files that need to use Vec. GF2::GF2(INIT_NO_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero GF2::GF2(INIT_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero GF2::allocate(); // provided for consistency with other classes, no action ntl-11.5.1/doc/GF2E.txt0000644417616742025610000002611014064716022016146 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2E SUMMARY: The class GF2E is used to represent polynomials in F_2[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. Objects of the class GF2E are represented as a GF2X of degree < deg(P). An executing program maintains a "current modulus", which is set to P using GF2E::init(P). The current modulus *must* be initialized before any operations on GF2E's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes GF2EPush and GF2EContext below). NOTE: if P is a trinomial X^n + X^k + 1, or a pentanomial X^n + X^k3 + X^k2 + X^k1 + 1, or of the form X^n + g, where g has low degree, then performance will be somewhat improved. Such polynomials are constructed by the routines BuildSparseIrred and BuildIrred in GF2XFactoring. \**************************************************************************/ #include #include class GF2E { public: GF2E(); // initial value 0 GF2E(const GF2E& a); // copy constructor explicit GF2E(GF2 a); // promotion constructor explicit GF2E(long a); // promotion constructor GF2E& operator=(const GF2E& a); // assignment GF2E& operator=(GF2 a); // assignment GF2E& operator=(long a); // assignment ~GF2E(); // destructor GF2E(GF2E&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN GF2E& operator=(GF2E&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif static void init(const GF2X& P); // GF2E::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const GF2XModulus& modulus(); // GF2E::modulus() yields read-only reference to the current modulus static long degree(); // GF2E::degree() returns deg(P) // typedefs to aid generic programming typedef GF2X rep_type; typedef GF2EContext context_type; typedef GF2EBak bak_type; typedef GF2EPush push_type; typedef GF2EX poly_type; }; const GF2X& rep(const GF2E& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2E& a, const GF2E& b); long operator!=(const GF2E& a, const GF2E& b); long IsZero(const GF2E& a); // test for 0 long IsOne(const GF2E& a); // test for 1 // PROMOTIONS: ==, != promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2E operator+(const GF2E& a, const GF2E& b); GF2E operator-(const GF2E& a, const GF2E& b); GF2E operator-(const GF2E& a); GF2E& operator+=(GF2E& x, const GF2E& a); GF2E& operator+=(GF2E& x, GF2 a); GF2E& operator+=(GF2E& x, long a); GF2E& operator++(GF2E& x); // prefix void operator++(GF2E& x, int); // postfix GF2E& operator-=(GF2E& x, const GF2E& a); GF2E& operator-=(GF2E& x, GF2 a); GF2E& operator-=(GF2E& x, long a); GF2E& operator--(GF2E& x); // prefix void operator--(GF2E& x, int); // postfix // procedural versions: void add(GF2E& x, const GF2E& a, const GF2E& b); // x = a + b void sub(GF2E& x, const GF2E& a, const GF2E& b); // x = a - b = a + b void negate(GF2E& x, const GF2E& a); // x = - a = a // PROMOTIONS: +, -, add, sub promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2E operator*(const GF2E& a, const GF2E& b); GF2E& operator*=(GF2E& x, const GF2E& a); GF2E& operator*=(GF2E& x, GF2 a); GF2E& operator*=(GF2E& x, long a); // procedural versions: void mul(GF2E& x, const GF2E& a, const GF2E& b); // x = a * b void sqr(GF2E& x, const GF2E& a); // x = a^2 GF2E sqr(const GF2E& a); // PROMOTIONS: *, mul promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2E operator/(const GF2E& a, const GF2E& b); GF2E& operator/=(GF2E& x, const GF2E& a); GF2E& operator/=(GF2E& x, GF2 a); GF2E& operator/=(GF2E& x, long a); // procedural versions: void div(GF2E& x, const GF2E& a, const GF2E& b); // x = a/b. If b is not invertible, an error is raised. void inv(GF2E& x, const GF2E& a); GF2E inv(const GF2E& a); // x = 1/a PROMOTIONS: /, div promote {long, GF2} to GF2E on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(GF2E& x, const GF2E& a, const ZZ& e); GF2E power(const GF2E& a, const ZZ& e); void power(GF2E& x, const GF2E& a, long e); GF2E power(const GF2E& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(GF2E& x); GF2E random_GF2E(); // x = random element in GF2E. /**************************************************************************\ Traces \**************************************************************************/ void trace(GF2& x, const GF2E& a); // x = trace of a GF2 trace(const GF2E& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const GF2E& a); istream& operator>>(istream& s, GF2E& x); // a GF2X is read and reduced mod p /**************************************************************************\ Modulus Switching A class GF2EPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { GF2EPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { GF2EPush push; // just backup current modulus ... GF2E::init(P1); // install P1 ... GF2E::init(P2); // install P2 // reinstall original modulus as close of scope } The GF2EPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see GF2EContext below. There is also an older GF2EBak class that may also be useful. .......................................................................... It is critical that GF2E objects created under one GF2E modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) GF2E modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any GF2E object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. NOTE: the implementation of Vec is specialized to manage memory more efficiently than in the default implementation of Vec. Specifically, contiguous elements in a Vec are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and --- more significantly --- leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec using the default or copy contructor, and to assign or append one Vec to another "out of context". \**************************************************************************/ // A convenient interface for common cases class GF2EPush { public: GF2EPush(); // backup current modulus explicit GF2EPush(const GF2X& P); explicit GF2EPush(const GF2EContext& context); // backup current modulus and install the given one private: GF2EPush(const GF2EPush&); // disabled void operator=(const GF2EPush&); // disabled }; // more general context switching: // A GF2EContext object has a modulus Q (possibly "null"), class GF2EContext { public: GF2EContext(); // Q = "null" explicit GF2EContext(const GF2X& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q GF2EContext(const GF2EContext&); // copy GF2EContext& operator=(const GF2EContext&); // assignment ~GF2EContext(); // destructor }; // An older interface: // To describe this logic, think of a GF2EBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class GF2EBak { public: GF2EBak(); // Q = "null", b = 0 ~GF2EBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: GF2EBak(const GF2EBak&); // copy disabled void operator=(const GF2EBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2E& x); // x = 0 void set(GF2E& x); // x = 1 static const GF2E& GF2E::zero(); // GF2E::zero() yields a read-only reference to zero static long GF2X::WordLength(); // GF2E::WordLength() returns # of words needed to store a polynomial of // degree < GF2E::degree() void GF2E::swap(GF2E& x); void swap(GF2E& x, GF2E& y); // swap (done by "pointer swapping", if possible). static ZZ& GF2E::cardinality(); // yields the cardinality, i.e., 2^{GF2E::degree()} GF2E::GF2E(INIT_NO_ALLOC_TYPE); // special constructor: invoke as GF2E x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) GF2E::GF2E(INIT_ALLOC_TYPE); // special constructor: invoke as GF2E x(INIT_ALLOC); // initializes x to 0, but allocates space GF2E::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-11.5.1/doc/GF2EX.txt0000644417616742025610000006612514064716022016310 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2EX SUMMARY: The class GF2EX represents polynomials over GF2E, and so can be used, for example, for arithmentic in GF(2^n)[X]. However, except where mathematically necessary (e.g., GCD computations), GF2E need not be a field. \**************************************************************************/ #include #include class GF2EX { public: GF2EX(); // initial value 0 GF2EX(const GF2EX& a); // copy explicit GF2EX(const GF2E& a); // promotion explicit GF2EX(GF2 a); explicit GF2EX(long a); GF2EX& operator=(const GF2EX& a); // assignment GF2EX& operator=(const GF2E& a); GF2EX& operator=(GF2 a); GF2EX& operator=(long a); ~GF2EX(); // destructor GF2EX(GF2EX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN GF2EX& operator=(GF2EX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif GF2EX(INIT_MONO_TYPE, long i, const GF2E& c); GF2EX(INIT_MONO_TYPE, long i, GF2 c); GF2EX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as GF2EX(INIT_MONO, i, c) GF2EX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as GF2EX(INIT_MONO, i) // typedefs to aid in generic programming typedef GF2E coeff_type; typedef GF2EXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const GF2EX& a); // return deg(a); deg(0) == -1. const GF2E& coeff(const GF2EX& a, long i); // returns the coefficient of X^i, or zero if i not in range const GF2E& LeadCoeff(const GF2EX& a); // returns leading term of a, or zero if a == 0 const GF2E& ConstTerm(const GF2EX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(GF2EX& x, long i, const GF2E& a); void SetCoeff(GF2EX& x, long i, GF2 a); void SetCoeff(GF2EX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(GF2EX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(GF2EX& x); // x is set to the monomial X long IsX(const GF2EX& a); // test if x = X GF2E& GF2EX::operator[](long i); const GF2E& GF2EX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void GF2EX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void GF2EX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void GF2EX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2EX& a, const GF2EX& b); long operator!=(const GF2EX& a, const GF2EX& b); long IsZero(const GF2EX& a); // test for 0 long IsOne(const GF2EX& a); // test for 1 // PROMOTIONS: ==, != promote {long,GF2,GF2E} to GF2EX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2EX operator+(const GF2EX& a, const GF2EX& b); GF2EX operator-(const GF2EX& a, const GF2EX& b); GF2EX operator-(const GF2EX& a); GF2EX& operator+=(GF2EX& x, const GF2EX& a); GF2EX& operator+=(GF2EX& x, const GF2E& a); GF2EX& operator+=(GF2EX& x, GF2 a); GF2EX& operator+=(GF2EX& x, long a); GF2EX& operator++(GF2EX& x); // prefix void operator++(GF2EX& x, int); // postfix GF2EX& operator-=(GF2EX& x, const GF2EX& a); GF2EX& operator-=(GF2EX& x, const GF2E& a); GF2EX& operator-=(GF2EX& x, GF2 a); GF2EX& operator-=(GF2EX& x, long a); GF2EX& operator--(GF2EX& x); // prefix void operator--(GF2EX& x, int); // postfix // procedural versions: void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b void sub(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a - b void negate(GF2EX& x, const GF2EX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,GF2,GF2E} to GF2EX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2EX operator*(const GF2EX& a, const GF2EX& b); GF2EX& operator*=(GF2EX& x, const GF2EX& a); GF2EX& operator*=(GF2EX& x, const GF2E& a); GF2EX& operator*=(GF2EX& x, GF2 a); GF2EX& operator*=(GF2EX& x, long a); // procedural versions: void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b void sqr(GF2EX& x, const GF2EX& a); // x = a^2 GF2EX sqr(const GF2EX& a); // PROMOTIONS: *, mul promote {long,GF2,GF2E} to GF2EX on (a, b). void power(GF2EX& x, const GF2EX& a, long e); // x = a^e (e >= 0) GF2EX power(const GF2EX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: GF2EX operator<<(const GF2EX& a, long n); GF2EX operator>>(const GF2EX& a, long n); GF2EX& operator<<=(GF2EX& x, long n); GF2EX& operator>>=(GF2EX& x, long n); // procedural versions: void LeftShift(GF2EX& x, const GF2EX& a, long n); GF2EX LeftShift(const GF2EX& a, long n); void RightShift(GF2EX& x, const GF2EX& a, long n); GF2EX RightShift(const GF2EX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2EX operator/(const GF2EX& a, const GF2EX& b); GF2EX operator/(const GF2EX& a, const GF2E& b); GF2EX operator/(const GF2EX& a, GF2 b); GF2EX operator/(const GF2EX& a, long b); GF2EX operator%(const GF2EX& a, const GF2EX& b); GF2EX& operator/=(GF2EX& x, const GF2EX& a); GF2EX& operator/=(GF2EX& x, const GF2E& a); GF2EX& operator/=(GF2EX& x, GF2 a); GF2EX& operator/=(GF2EX& x, long a); GF2EX& operator%=(GF2EX& x, const GF2EX& a); // procedural versions: void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b); // q = a/b, r = a%b void div(GF2EX& q, const GF2EX& a, const GF2EX& b); void div(GF2EX& q, const GF2EX& a, const GF2E& b); void div(GF2EX& q, const GF2EX& a, GF2 b); void div(GF2EX& q, const GF2EX& a, long b); // q = a/b void rem(GF2EX& r, const GF2EX& a, const GF2EX& b); // r = a%b long divide(GF2EX& q, const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2EX& a, const GF2EX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when GF2E is a field. \**************************************************************************/ void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b); GF2EX GCD(const GF2EX& a, const GF2EX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < GF2E::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo GF2E::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, GF2EX& x); ostream& operator<<(ostream& s, const GF2EX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(GF2EX& x, const GF2EX& a); // x = derivative of a GF2EX diff(const GF2EX& a); void MakeMonic(GF2EX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(GF2EX& x, const GF2EX& a, long hi); GF2EX reverse(const GF2EX& a, long hi); void reverse(GF2EX& x, const GF2EX& a); GF2EX reverse(const GF2EX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_GF2E& x, const GF2EX& a, long n); vec_GF2E VectorCopy(const GF2EX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(GF2EX& x, long n); GF2EX random_GF2EX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(GF2EX& x, const vec_GF2E& a); GF2EX BuildFromRoots(const vec_GF2E& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(GF2E& b, const GF2EX& f, const GF2E& a); GF2E eval(const GF2EX& f, const GF2E& a); // b = f(a) void eval(GF2E& b, const GF2X& f, const GF2E& a); GF2E eval(const GF2EX& f, const GF2E& a); // b = f(a); uses ModComp algorithm for GF2X void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a); vec_GF2E eval(const GF2EX& f, const vec_GF2E& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b); GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(GF2EX& x, const GF2EX& a, long n); // x = a % X^n GF2EX trunc(const GF2EX& a, long n); void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n); GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n); // x = a * b % X^n void SqrTrunc(GF2EX& x, const GF2EX& a, long n); GF2EX SqrTrunc(const GF2EX& a, long n); // x = a^2 % X^n void InvTrunc(GF2EX& x, const GF2EX& a, long n); GF2EX InvTrunc(GF2EX& x, const GF2EX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the GF2EXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f); GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f); // x = (a * b) % f void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX SqrMod(const GF2EX& a, const GF2EX& f); // x = a^2 % f void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX MulByXMod(const GF2EX& a, const GF2EX& f); // x = (a * X) mod f void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f); GF2EX InvMod(const GF2EX& a, const GF2EX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build GF2EXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(GF2EX& x, const vec_GF2EX& v, const GF2EX& f) { GF2EXModulus F(f); GF2EX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A GF2EX may be used wherever a GF2EXModulus is required, and a GF2EXModulus may be used wherever a GF2EX is required. \**************************************************************************/ class GF2EXModulus { public: GF2EXModulus(); // initially in an unusable state GF2EXModulus(const GF2EX& f); // initialize with f, deg(f) > 0 GF2EXModulus(const GF2EXModulus&); // copy GF2EXModulus& operator=(const GF2EXModulus&); // assignment ~GF2EXModulus(); // destructor operator const GF2EX& () const; // implicit read-only access to f const GF2EX& val() const; // explicit read-only access to f }; void build(GF2EXModulus& F, const GF2EX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration GF2EXModulus F(f) is // equivalent to GF2EXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const GF2EXModulus& F); // return n=deg(f) void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(GF2EX& x, const GF2EX& a, const GF2EXModulus& F); GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(GF2EX& x, const GF2EX& a, const ZZ& e, const GF2EXModulus& F); GF2EX PowerMod(const GF2EX& a, const ZZ& e, const GF2EXModulus& F); void PowerMod(GF2EX& x, const GF2EX& a, long e, const GF2EXModulus& F); GF2EX PowerMod(const GF2EX& a, long e, const GF2EXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(GF2EX& x, const ZZ& e, const GF2EXModulus& F); GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F); void PowerXMod(GF2EX& x, long e, const GF2EXModulus& F); GF2EX PowerXMod(long e, const GF2EXModulus& F); // x = X^e % f (e may be negative) void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F); // x = a % f void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F); // q = a/f, r = a%f void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F); // q = a/f // operator notation: GF2EX operator/(const GF2EX& a, const GF2EXModulus& F); GF2EX operator%(const GF2EX& a, const GF2EXModulus& F); GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F); GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F); /**************************************************************************\ vectors of GF2EX's \**************************************************************************/ typedef Vec vec_GF2EX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); GF2EX CompMod(const GF2EX& g, const GF2EX& h, const GF2EXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3, const GF2EX& g1, const GF2EX& g2, const GF2EX& g3, const GF2EX& h, const GF2EXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a GF2EXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct GF2EXArgument { vec_GF2EX H; }; void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H, const GF2EXModulus& F); extern thread_local long GF2EXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // GF2EXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in GF2EXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(GF2E& x, const GF2EVector& a, const GF2EX& b); GF2E project(const GF2EVector& a, const GF2EX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EX& h, const GF2EXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); vec_GF2E ProjectPowers(const vec_GF2E& a, long k, const GF2EXArgument& H, const GF2EXModulus& F); // same as above, but uses a pre-computed GF2EXArgument class GF2EXTransMultiplier { /* ... */ }; void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F); void UpdateMap(vec_GF2E& x, const vec_GF2E& a, const GF2EXMultiplier& B, const GF2EXModulus& F); vec_GF2E UpdateMap(const vec_GF2E& a, const GF2EXMultiplier& B, const GF2EXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when GF2E is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m); GF2EX MinPolySeq(const vec_GF2E& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{GF2E::degree()}. void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m); void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F); GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. GF2E need not be a field. \**************************************************************************/ void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& h, const GF2EXModulus& F); GF2EX CompTower(const GF2X& g, const GF2EXArgument& h, const GF2EXModulus& F); void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h, const GF2EXModulus& F); GF2EX CompTower(const GF2X& g, const GF2EX& h, const GF2EXModulus& F); // x = g(h) mod f void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over GF2. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*GF2E::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m); GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m); void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F); GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F); GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F); void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f); GF2E TraceMod(const GF2EX& a, const GF2EXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_GF2E& S, const GF2EX& f); vec_GF2E TraceVec(const GF2EX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f); GF2E NormMod(const GF2EX& a, const GF2EX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(GF2E& x, const GF2EX& a, const GF2EX& b); GF2E resultant(const GF2EX& a, const GF2EX& b); // x = resultant(a, b) // NormMod and resultant require that GF2E is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2EX& x) // x = 0 void set(GF2EX& x); // x = 1 void GF2EX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). GF2EX::GF2EX(INIT_SIZE_TYPE, long n); // GF2EX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const GF2EX& zero(); // GF2EX::zero() is a read-only reference to 0 void GF2EX::swap(GF2EX& x); void swap(GF2EX& x, GF2EX& y); // swap (via "pointer swapping") GF2EX::GF2EX(long i, const GF2E& c); GF2EX::GF2EX(long i, GF2 c); GF2EX::GF2EX(long i, long c); // initialize to X^i*c, provided for backward compatibility ntl-11.5.1/doc/GF2EXFactoring.txt0000644417616742025610000002001314064716022020127 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2EXFactoring SUMMARY: Routines are provided for factorization of polynomials over GF2E, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f); vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_GF2E& x, const GF2EX& f); vec_GF2E FindRoots(const GF2EX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(GF2E& root, const GF2EX& f); GF2E FindRoot(const GF2EX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX SFBerlekamp(const GF2EX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h, long verbose=0); vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{2^{GF2E::degree()}} mod f, // which can be computed efficiently using the function FrobeniusMap // (see below). // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995], // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form tmp-*. // The definition of "large" is controlled by the variable extern thread_local double GF2EXFileThresh // which can be set by the user. If the sizes of the tables // exceeds GF2EXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& h, long d, long verbose=0); vec_GF2EX EDF(const GF2EX& f, const GF2EX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. // h = X^{2^{GF2E::degree()}} mod f, // which can be computed efficiently using the function FrobeniusMap // (see below). // d = degree of irreducible factors of f. // This routine implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX RootEDF(const GF2EX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0); vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f, long verbose=0); vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // GF2EXArgBound (see GF2EX.txt). // NOTE: In most situations, you should use the CanZass factoring // routine, rather than Berlekamp: it is faster and uses less space. void mul(GF2EX& f, const vec_pair_GF2EX_long& v); GF2EX mul(const vec_pair_GF2EX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const GF2EX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // 2^{-iter*GF2E::degree()}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const GF2EX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const GF2EX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(GF2EX& f, long n); GF2EX BuildIrred_GF2EX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(GF2EX& f, const GF2EX& g); GF2EX BuildRandomIrred(const GF2EX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. void FrobeniusMap(GF2EX& h, const GF2EXModulus& F); GF2EX FrobeniusMap(const GF2EXModulus& F); // Computes h = X^{2^{GF2E::degree()}} mod F, // by either iterated squaring or modular // composition. The latter method is based on a technique developed // in Kaltofen & Shoup (Faster polynomial factorization over high // algebraic extensions of finite fields, ISSAC 1997). This method is // faster than iterated squaring when deg(F) is large relative to // GF2E::degree(). long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{2^{GF2E::degree()}} mod f (see function FrobeniusMap above) // The common degree of the irreducible factors // of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F); // f is assumed to be an "equal degree" polynomial, h = X^{2^{GF2E::degree()}} // mod f (see function FrobeniusMap above). // The common degree of the irreducible factors of f is // computed. Uses a recursive algorithm similar to DetIrredTest. void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& h); GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F, const GF2EX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of 2^{GF2E::degree()}. This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992]. // If q = 2^{GF2E::degree()}, then h can be computed most efficiently // by using the function FrobeniusMap above. void PowerCompose(GF2EX& w, const GF2EX& h, long d, const GF2EXModulus& F); GF2EX PowerCompose(const GF2EX& h, long d, const GF2EXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of 2^{GF2E::degree()}. This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992]. // If q = 2^{GF2E::degree()}, then h can be computed most efficiently // by using the function FrobeniusMap above. ntl-11.5.1/doc/GF2X.txt0000644417616742025610000006124514064716022016201 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2X SUMMARY: The class GF2X implements polynomial arithmetic modulo 2. Polynomial arithmetic is implemented using a combination of classical routines and Karatsuba. \**************************************************************************/ #include #include class GF2X { public: GF2X(); // initial value 0 GF2X(const GF2X& a); // copy explicit GF2X(long a); // promotion explicit GF2X(GF2 a); // promotion GF2X& operator=(const GF2X& a); // assignment GF2X& operator=(GF2 a); GF2X& operator=(long a); ~GF2X(); // destructor GF2X(GF2X&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN GF2X& operator=(GF2X&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif GF2X(INIT_MONO_TYPE, long i, GF2 c); GF2X(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as GF2X(INIT_MONO, i, c) GF2X(INIT_MONO_TYPE, long i); // initialize to c*X^i, invoke as GF2X(INIT_MONO, i) // typedefs to aid in generic programming typedef GF2 coeff_type; typedef GF2E residue_type; typedef GF2XModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: unlike other polynomial classes, the coefficient vector for GF2X has a special representation, packing coefficients into words. This has two consequences. First, when using the indexing notation on a non-const polynomial f, the return type is ref_GF2, rather than GF2&. For the most part, a ref_GF2 may be used like a GF2& --- see GF2.txt for more details. Second, when applying f.SetLength(n) to a polynomial f, this essentially has the effect of zeroing out the coefficients of X^i for i >= n. \**************************************************************************/ long deg(const GF2X& a); // return deg(a); deg(0) == -1. const GF2 coeff(const GF2X& a, long i); // returns the coefficient of X^i, or zero if i not in range const GF2 LeadCoeff(const GF2X& a); // returns leading term of a, or zero if a == 0 const GF2 ConstTerm(const GF2X& a); // returns constant term of a, or zero if a == 0 void SetCoeff(GF2X& x, long i, GF2 a); void SetCoeff(GF2X& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(GF2X& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(GF2X& x); // x is set to the monomial X long IsX(const GF2X& a); // test if x = X ref_GF2 GF2X::operator[](long i); const GF2 GF2X::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f) void GF2X::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void GF2X::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void GF2X::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const GF2X& a, const GF2X& b); long operator!=(const GF2X& a, const GF2X& b); long IsZero(const GF2X& a); // test for 0 long IsOne(const GF2X& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, GF2} to GF2X on (a, b) /**************************************************************************\ Addition \**************************************************************************/ // operator notation: GF2X operator+(const GF2X& a, const GF2X& b); GF2X operator-(const GF2X& a, const GF2X& b); GF2X operator-(const GF2X& a); // unary - GF2X& operator+=(GF2X& x, const GF2X& a); GF2X& operator+=(GF2X& x, GF2 a); GF2X& operator+=(GF2X& x, long a); GF2X& operator-=(GF2X& x, const GF2X& a); GF2X& operator-=(GF2X& x, GF2 a); GF2X& operator-=(GF2X& x, long a); GF2X& operator++(GF2X& x); // prefix void operator++(GF2X& x, int); // postfix GF2X& operator--(GF2X& x); // prefix void operator--(GF2X& x, int); // postfix // procedural versions: void add(GF2X& x, const GF2X& a, const GF2X& b); // x = a + b void sub(GF2X& x, const GF2X& a, const GF2X& b); // x = a - b void negate(GF2X& x, const GF2X& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, GF2} // to GF2X on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: GF2X operator*(const GF2X& a, const GF2X& b); GF2X& operator*=(GF2X& x, const GF2X& a); GF2X& operator*=(GF2X& x, GF2 a); GF2X& operator*=(GF2X& x, long a); // procedural versions: void mul(GF2X& x, const GF2X& a, const GF2X& b); // x = a * b void sqr(GF2X& x, const GF2X& a); // x = a^2 GF2X sqr(const GF2X& a); // PROMOTIONS: operator * and procedure mul promote {long, GF2} to GF2X // on (a, b). /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: GF2X operator<<(const GF2X& a, long n); GF2X operator>>(const GF2X& a, long n); GF2X& operator<<=(GF2X& x, long n); GF2X& operator>>=(GF2X& x, long n); // procedural versions: void LeftShift(GF2X& x, const GF2X& a, long n); GF2X LeftShift(const GF2X& a, long n); void RightShift(GF2X& x, const GF2X& a, long n); GF2X RightShift(const GF2X& a, long n); void MulByX(GF2X& x, const GF2X& a); GF2X MulByX(const GF2X& a); /**************************************************************************\ Division \**************************************************************************/ // operator notation: GF2X operator/(const GF2X& a, const GF2X& b); GF2X operator%(const GF2X& a, const GF2X& b); GF2X& operator/=(GF2X& x, const GF2X& a); GF2X& operator/=(GF2X& x, GF2 a); GF2X& operator/=(GF2X& x, long a); GF2X& operator%=(GF2X& x, const GF2X& b); // procedural versions: void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b); // q = a/b, r = a%b void div(GF2X& q, const GF2X& a, const GF2X& b); // q = a/b void rem(GF2X& r, const GF2X& a, const GF2X& b); // r = a%b long divide(GF2X& q, const GF2X& a, const GF2X& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const GF2X& a, const GF2X& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 // PROMOTIONS: operator / and procedure div promote {long, GF2} to GF2X // on (a, b). /**************************************************************************\ GCD's \**************************************************************************/ void GCD(GF2X& x, const GF2X& a, const GF2X& b); GF2X GCD(const GF2X& a, const GF2X& b); // x = GCD(a, b) (zero if a==b==0). void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be 0 or 1, and a_n not zero (the zero polynomial is [ ]). On input, the coefficients may be arbitrary integers which are reduced modulo 2, and leading zeros stripped. There is also a more compact hex I/O format. To output in this format, set GF2X::HexOutput to a nonzero value. On input, if the first non-blank character read is 'x' or 'X', then a hex format is assumed. \**************************************************************************/ istream& operator>>(istream& s, GF2X& x); ostream& operator<<(ostream& s, const GF2X& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(GF2X& x, const GF2X& a); GF2X diff(const GF2X& a); // x = derivative of a void reverse(GF2X& x, const GF2X& a, long hi); GF2X reverse(const GF2X& a, long hi); void reverse(GF2X& x, const GF2X& a); GF2X reverse(const GF2X& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_GF2& x, const GF2X& a, long n); vec_GF2 VectorCopy(const GF2X& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. // Note that there is also a conversion routine from GF2X to vec_GF2 // that makes the length of the vector match the number of coefficients // of the polynomial. long weight(const GF2X& a); // returns the # of nonzero coefficients in a void GF2XFromBytes(GF2X& x, const unsigned char *p, long n); GF2X GF2XFromBytes(const unsigned char *p, long n); // conversion from byte vector to polynomial. // x = sum(p[i]*X^(8*i), i = 0..n-1), where the bits of p[i] are interpretted // as a polynomial in the natural way (i.e., p[i] = 1 is interpretted as 1, // p[i] = 2 is interpretted as X, p[i] = 3 is interpretted as X+1, etc.). // In the unusual event that characters are wider than 8 bits, // only the low-order 8 bits of p[i] are used. void BytesFromGF2X(unsigned char *p, const GF2X& a, long n); // conversion from polynomial to byte vector. // p[0..n-1] are computed so that // a = sum(p[i]*X^(8*i), i = 0..n-1) mod X^(8*n), // where the values p[i] are interpretted as polynomials as in GF2XFromBytes // above. long NumBits(const GF2X& a); // returns number of bits of a, i.e., deg(a) + 1. long NumBytes(const GF2X& a); // returns number of bytes of a, i.e., floor((NumBits(a)+7)/8) /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(GF2X& x, long n); GF2X random_GF2X(long n); // x = random polynomial of degree < n /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(GF2X& x, const GF2X& a, long n); // x = a % X^n GF2X trunc(const GF2X& a, long n); void MulTrunc(GF2X& x, const GF2X& a, const GF2X& b, long n); GF2X MulTrunc(const GF2X& a, const GF2X& b, long n); // x = a * b % X^n void SqrTrunc(GF2X& x, const GF2X& a, long n); GF2X SqrTrunc(const GF2X& a, long n); // x = a^2 % X^n void InvTrunc(GF2X& x, const GF2X& a, long n); GF2X InvTrunc(const GF2X& a, long n); // computes x = a^{-1} % X^n. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the GF2XModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2X& f); GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f); // x = (a * b) % f void SqrMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X SqrMod(const GF2X& a, const GF2X& f); // x = a^2 % f void MulByXMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X MulByXMod(const GF2X& a, const GF2X& f); // x = (a * X) mod f void InvMod(GF2X& x, const GF2X& a, const GF2X& f); GF2X InvMod(const GF2X& a, const GF2X& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(GF2X& x, const GF2X& a, const GF2X& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build GF2XModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine computes the product modulo f of a vector of polynomials. #include void product(GF2X& x, const vec_GF2X& v, const GF2X& f) { GF2XModulus F(f); GF2X res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a GF2X can be used wherever a GF2XModulus is required, and a GF2XModulus can be used wherever a GF2X is required. The GF2XModulus routines optimize several important special cases: - f = X^n + X^k + 1, where k <= min((n+1)/2, n-NTL_BITS_PER_LONG) - f = X^n + X^{k_3} + X^{k_2} + X^{k_1} + 1, where k_3 <= min((n+1)/2, n-NTL_BITS_PER_LONG) - f = X^n + g, where deg(g) is small \**************************************************************************/ class GF2XModulus { public: GF2XModulus(); // initially in an unusable state ~GF2XModulus(); GF2XModulus(const GF2XModulus&); // copy GF2XModulus& operator=(const GF2XModulus&); // assignment GF2XModulus(const GF2X& f); // initialize with f, deg(f) > 0 operator const GF2X& () const; // read-only access to f, implicit conversion operator const GF2X& val() const; // read-only access to f, explicit notation long WordLength() const; // returns word-length of resisues }; void build(GF2XModulus& F, const GF2X& f); // pre-computes information about f and stores it in F; deg(f) > 0. // Note that the declaration GF2XModulus F(f) is equivalent to // GF2XModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const GF2XModulus& F); // return deg(f) void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2XModulus& F); GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(GF2X& x, const GF2X& a, const GF2XModulus& F); GF2X SqrMod(const GF2X& a, const GF2XModulus& F); // x = a^2 % f; deg(a) < n void MulByXMod(GF2X& x, const GF2X& a, const GF2XModulus& F); GF2X MulByXMod(const GF2X& a, const GF2XModulus& F); // x = (a * X) mod F void PowerMod(GF2X& x, const GF2X& a, const ZZ& e, const GF2XModulus& F); GF2X PowerMod(const GF2X& a, const ZZ& e, const GF2XModulus& F); void PowerMod(GF2X& x, const GF2X& a, long e, const GF2XModulus& F); GF2X PowerMod(const GF2X& a, long e, const GF2XModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(GF2X& x, const ZZ& e, const GF2XModulus& F); GF2X PowerXMod(const ZZ& e, const GF2XModulus& F); void PowerXMod(GF2X& x, long e, const GF2XModulus& F); GF2X PowerXMod(long e, const GF2XModulus& F); // x = X^e % f (e may be negative) void rem(GF2X& x, const GF2X& a, const GF2XModulus& F); // x = a % f void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F); // q = a/f, r = a%f void div(GF2X& q, const GF2X& a, const GF2XModulus& F); // q = a/f // operator notation: GF2X operator/(const GF2X& a, const GF2XModulus& F); GF2X operator%(const GF2X& a, const GF2XModulus& F); GF2X& operator/=(GF2X& x, const GF2XModulus& F); GF2X& operator%=(GF2X& x, const GF2XModulus& F); /**************************************************************************\ vectors of GF2X's \**************************************************************************/ typedef Vec vec_GF2X; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F); GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2, const GF2X& h, const GF2XModulus& F); // xi = gi(h) mod f (i=1,2), deg(h) < n. void CompMod3(GF2X& x1, GF2X& x2, GF2X& x3, const GF2X& g1, const GF2X& g2, const GF2X& g3, const GF2X& h, const GF2XModulus& F); // xi = gi(h) mod f (i=1..3), deg(h) < n /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a GF2XArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct GF2XArgument { vec_GF2X H; }; void build(GF2XArgument& H, const GF2X& h, const GF2XModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& H, const GF2XModulus& F); GF2X CompMod(const GF2X& g, const GF2XArgument& H, const GF2XModulus& F); extern thread_local long GF2XArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // GF2XArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in GF2XFactoring. /**************************************************************************\ Power Projection routines \**************************************************************************/ void project(GF2& x, const vec_GF2& a, const GF2X& b); GF2 project(const vec_GF2& a, const GF2X& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2X& h, const GF2XModulus& F); // Computes the vector // (project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // Restriction: must have a.length <= deg(F) and deg(h) < deg(F). // This operation is really the "transpose" of the modular composition // operation. void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); vec_GF2 ProjectPowers(const vec_GF2& a, long k, const GF2XArgument& H, const GF2XModulus& F); // same as above, but uses a pre-computed GF2XArgument // lower-level routines for transposed modular multiplication: class GF2XTransMultiplier { /* ... */ }; void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F); // build a GF2XTransMultiplier to use in the following routine: void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B, const GF2XModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: must have a.length() <= deg(F) and deg(b) < deg(F). // This is really the transpose of modular multiplication. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(GF2X& h, const vec_GF2& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m); void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic; it always // returns a divisor of the minimal polynomial, possibly a proper divisor. void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m); void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m); GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m); void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F); GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F); // same as above, but assumes that F is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces \**************************************************************************/ void TraceMod(GF2& x, const GF2X& a, const GF2XModulus& F); GF2 TraceMod(const GF2X& a, const GF2XModulus& F); void TraceMod(GF2& x, const GF2X& a, const GF2X& f); GF2 TraceMod(const GF2X& a, const GF2X& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_GF2& S, const GF2X& f); vec_GF2 TraceVec(const GF2X& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(GF2X& x) // x = 0 void set(GF2X& x); // x = 1 void GF2X::kill(); // f.kill() sets f to 0 and frees all memory held by f. GF2X::GF2X(INIT_SIZE_TYPE, long n); // GF2X(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const GF2X& zero(); // GF2X::zero() is a read-only reference to 0 void GF2X::swap(GF2X& x); void swap(GF2X& x, GF2X& y); // swap (via "pointer swapping" -- if possible) GF2X::GF2X(long i, GF2 c); GF2X::GF2X(long i, long c); // initialize to c*X^i, provided for backward compatibility // SIZE INVARIANT: for any f in GF2X, deg(f)+1 < 2^(NTL_BITS_PER_LONG-4). ntl-11.5.1/doc/GF2XFactoring.txt0000644417616742025610000000775614064716022020045 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2XFactoring SUMMARY: Routines are provided for factorization in F_2[X], as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& f); vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void DDF(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. void EDF(vec_GF2X& factors, const GF2X& f, long d, long verbose=0); vec_GF2X EDF(const GF2X& f, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. d = degree of // irreducible factors of f void SFCanZass(vec_GF2X& factors, const GF2X& f, long verbose=0); vec_GF2X SFCanZass(const GF2X& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0); vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. void mul(GF2X& f, const vec_pair_GF2X_long& v); GF2X mul(const vec_pair_GF2X_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long IterIrredTest(const GF2X& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildSparseIrred(GF2X& f, long n); GF2X BuildSparseIrred_GF2X(long n); // Builds a monic irreducible polynomial of degree n. // If there is an irreducible trinomial X^n + X^k + 1, // then the one with minimal k is chosen. // Otherwise, if there is an irreducible pentanomial // X^n + X^k3 + X^k2 + x^k1 + 1, then the one with minimal // k3 is chosen (minimizing first k2 and then k1). // Otherwise, if there is niether an irreducible trinomial // or pentanomial, the routine result from BuildIrred (see below) // is chosen---this is probably only of academic interest, // since it a reasonable, but unproved, conjecture that they // exist for every n > 1. // For n <= 2048, the polynomial is constructed // by table lookup in a pre-computed table. // The GF2XModulus data structure and routines (and indirectly GF2E) // are optimized to deal with the output from BuildSparseIrred. void BuildIrred(GF2X& f, long n); GF2X BuildIrred_GF2X(long n); // Build a monic irreducible poly of degree n. The polynomial // constructed is "canonical" in the sense that it is of the form // f=X^n + g, where the bits of g are the those of the smallest // non-negative integer that make f irreducible. // The GF2XModulus data structure and routines (and indirectly GF2E) // are optimized to deal with the output from BuildIrred. // Note that the output from BuildSparseIrred will generally yield // a "better" representation (in terms of efficiency) for // GF(2^n) than the output from BuildIrred. void BuildRandomIrred(GF2X& f, const GF2X& g); GF2X BuildRandomIrred(const GF2X& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. ntl-11.5.1/doc/GF2XVec.txt0000644417616742025610000000347714064716022016642 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: GF2XVec SUMMARY: The class GF2XVec implements vectors of fixed-length GF2X's. You can allocate a vector of GF2X's of a specified length, where the maximum size of each GF2X is also specified. These parameters can be specified either with a constructor, or with SetSize. It is an error to try to re-size a vector of non-xero , or store a GF2X that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_GF2X. \**************************************************************************/ #include class GF2XVec { public: GF2XVec(); GF2XVec& operator=(const GF2XVec&); // first kill()'s destination (unless source and destination are // identical) GF2XVec(const GF2XVec&); ~GF2XVec(); GF2XVec(GF2XVec&& other) noexcept; GF2XVec& operator=(GF2XVec&& other) noexcept; GF2XVec(long n, long d); // sets length to n and max size of each element to d, // where the size d measures the number of words void SetSize(long n, long d); // sets length to n and max size of each element to d, // where the size d measures the number of words long length() const; // length of vector long BaseSize() const; // max size of each element void kill(); // release space GF2X* elts(); const GF2X* elts() const; // pointer to first element GF2X& operator[](long i); const GF2X& operator[](long i) const; // indexing operator; starts at 0; no range checking swap(GF2XVec& x); // swap with x by swapping pointers void move(GF2XVec& other); // quick move other to *this }; void swap(GF2XVec& x, GF2XVec& y); // swaps x and y by swapping pointers ntl-11.5.1/doc/HNF.txt0000644417616742025610000000161214064716022016076 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: HNF SUMMARY: A routine for computing Hermite Normal Forms \**************************************************************************/ #include void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D); // The input matrix A is an n x m matrix of rank m (so n >= m), and D // is a multiple of the determinant of the lattice L spanned by the // rows of A. W is computed as the Hermite Normal Form of A; that is, // W is the unique m x m matrix whose rows span L, such that // - W is lower triangular, // - the diagonal entries are positive, // - any entry below the diagonal is a non-negative number // strictly less than the diagonal entry in its column. // Currently, this is implemented using the algorithm of [P. Domich, // R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. ntl-11.5.1/doc/Lazy.txt0000644417616742025610000000546714064716022016416 0ustar gid-shoupvpug-gid-shoupv /*************************************************************************** Lazy: template class for lazy initialization of objects whose values do not change after initialization. In a multi-threaded environment, this makes use of "double checked locking" for an efficient, thread-safe solution. Usage: Lazy obj; // declaration of the lazy object ... do { Lazy::Builder builder(obj); if (!builder()) break; // if we are not building, the break out UniquePtr p; // create a pointer ... builder.move(p); // move p into the object to complete the initialization // We can then complete the initialization process. } while(0); // When this scope closes, the object is fully initialized. // subsequent attempts to build the object will yield // !builder.built() T objCopy = *obj; // *obj returns a read-only reference // one can also use -> operator It is important to follow this recipe carefully. In particular, the builder must be enclosed in a scope, as it's destructor plays a crucial role in finalizing the initialization. NOTE: if p is null in builder.move(p), the object is still considered built. ****************************************************************************/ template class Lazy { public: Lazy(); Lazy(const Lazy&); Lazy& operator=(const Lazy&); // deep copies using T's copy constructor // EXCEPTIONS: may throw (but provides strong ES guarantee) const T& operator*() const; // pointer access const T* operator->() const; const T* get() const; operator fake_null_type() const; // allows test against 0 ~Lazy(); kill(); // destroy and reset bool built() const; // test if already built class Builder { Builder(const Lazy&); ~Builder() bool operator()() const; // test if we are building void move(UniquePtr&); // EXCEPTIONS: may throw an exception if the move is not allowed // (i.e., not building or already moved). // Provides strong ES guarantee. }; }; // EXCEPTIONS: except where noted, no exceptions are thrown // NOTE: For more on double-checked locking, see // http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ // NOTE: when compiled with the NTL_THREADS option, the Lazy // class may contain data members from the standard library // that may not satisfy the requirements of the Vec class // (i.e., relocatability). One can wrap it in a pointer // class (e.g., CopiedPtr) to deal with this. // NOTE: The optional parameter P is used as in the specification // of the UniquePtr class. The default should work fine in // most cases. It was introduced mainly to allow for the PIMPL // paradigm. ntl-11.5.1/doc/LazyTable.txt0000644417616742025610000000462514064716022017361 0ustar gid-shoupvpug-gid-shoupv /*************************************************************************** LazyTable: template class for lazy initialization of objects whose values do not change after initialization. In a multi-threaded environment, this makes use of "double checked locking" for an efficient, thread-safe solution. Usage: LazyTable tab; // declaration of the lazy table, // with max size == MAX ... do { LazyTable::Builder builder(tab, n); // request length n long amt = builder.amt(); if (!amt) break; ... initialize elements i = n-amt..n-1 using builder.move(p), where p is a UnqiuePtr note that each move application appends one element } while(0); // When this scope closes, // the table is fully initialized to length n const T* val = table[i]; // read-only access to table elements 0..n-1 It is important to follow this recipe carefully. In particular, the builder must be enclosed in a scope, as it's destructor plays a crucial role in finalizing the initialization. ****************************************************************************/ template class LazyTable { public: LazyTable(); ~LazyTable(); const T * const operator[] (long i) const; // element access -- currently no range checking long length() const; // current table length class Builder { Builder(const LazyTable&, long request); // EXCEPTIONS: may throw an exception if request is out of range // or if alocation of table fails ~Builder() long amt() const; void move(UniquePtr& p); // EXCEPTIONS: throws exception of move is not allowed. // Provides strong ES guarantee. }; private: LazyTable(const LazyTable&); // disabled LazyTable& operator=(const LazyTable&); }; // EXCEPTIONS: except where noted, no exceptions are thrown // NOTE: For more on double-checked locking, see // http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ // NOTE: when compiled with the NTL_THREADS option, the LazyTable // class may contain data members from the standard library // that may not satisfy the requirements of the Vec class // (i.e., relocatability). One can wrap it in a pointer // class (e.g., CopiedPtr) to deal with this. ntl-11.5.1/doc/LLL.txt0000644417616742025610000004215314064716022016113 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: LLL SUMMARY: Routines are provided for lattice basis reduction, including both exact-aritmetic variants (slow but sure) and floating-point variants (fast but only approximate). For an introduction to the basics of LLL reduction, see [H. Cohen, A Course in Computational Algebraic Number Theory, Springer, 1993]. The LLL algorithm was introduced in [A. K. Lenstra, H. W. Lenstra, and L. Lovasz, Math. Ann. 261 (1982), 515-534]. \**************************************************************************/ #include /**************************************************************************\ Exact Arithmetic Variants \**************************************************************************/ long LLL(ZZ& det2, mat_ZZ& B, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, long a, long b, long verbose = 0); long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); // performs LLL reduction. // B is an m x n matrix, viewed as m rows of n-vectors. m may be less // than, equal to, or greater than n, and the rows need not be // linearly independent. B is transformed into an LLL-reduced basis, // and the return value is the rank r of B. The first m-r rows of B // are zero. // More specifically, elementary row transformations are performed on // B so that the non-zero rows of new-B form an LLL-reduced basis // for the lattice spanned by the rows of old-B. // The default reduction parameter is delta=3/4, which means // that the squared length of the first non-zero basis vector // is no more than 2^{r-1} times that of the shortest vector in // the lattice. // det2 is calculated as the *square* of the determinant // of the lattice---note that sqrt(det2) is in general an integer // only when r = n. // In the second version, U is set to the transformation matrix, so // that U is a unimodular m x m matrix with U * old-B = new-B. // Note that the first m-r rows of U form a basis (as a lattice) // for the kernel of old-B. // The third and fourth versions allow an arbitrary reduction // parameter delta=a/b, where 1/4 < a/b <= 1, where a and b are positive // integers. // For a basis reduced with parameter delta, the squared length // of the first non-zero basis vector is no more than // 1/(delta-1/4)^{r-1} times that of the shortest vector in the // lattice (see, e.g., the article by Schnorr and Euchner mentioned below). // The algorithm employed here is essentially the one in Cohen's book. // Some variations: long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose = 0); long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0); // These are variations that return a bit more information about the // reduced basis. If r is the rank of B, then D is a vector of length // r+1, such that D[0] = 1, and for i = 1..r, D[i]/D[i-1] is equal to // the square of the length of the i-th vector of the Gram-Schmidt basis // corresponding to the (non-zero) rows of the LLL reduced basis B. // In particular, D[r] is equal to the value det2 computed by the // plain LLL routines. /**************************************************************************\ Computing Images and Kernels \**************************************************************************/ long image(ZZ& det2, mat_ZZ& B, long verbose = 0); long image(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0); // This computes the image of B using a "cheap" version of the LLL: // it performs the usual "size reduction", but it only swaps // vectors when linear dependencies are found. // I haven't seen this described in the literature, but it works // fairly well in practice, and can also easily be shown // to run in a reasonable amount of time with reasonably bounded // numbers. // As in the above LLL routines, the return value is the rank r of B, and the // first m-r rows will be zero. U is a unimodular m x m matrix with // U * old-B = new-B. det2 has the same meaning as above. // Note that the first m-r rows of U form a basis (as a lattice) // for the kernel of old-B. // This is a reasonably practical algorithm for computing kernels. // One can also apply image() to the kernel to get somewhat // shorter basis vectors for the kernels (there are no linear // dependencies, but the size reduction may anyway help). // For even shorter kernel basis vectors, on can apply // LLL(). /**************************************************************************\ Finding a vector in a lattice \**************************************************************************/ long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0); // This tests if for given A and y, there exists x such that x*A = y; // if so, x is set to a solution, and the value 1 is returned; // otherwise, x is left unchanged, and the value 0 is returned. // The optional parameter reduce controls the 'quality' of the // solution vector; if the rows of A are linearly dependent, // there are many solutions, if there are any at all. // The value of reduce controls the amount of effort that goes // into finding a 'short' solution vector x. // reduce = 0: No particular effort is made to find a short solution. // reduce = 1: A simple 'size reduction' algorithm is run on kernel(A); // this is fast, and may yield somewhat shorter // solutions than the default, but not necessarily // very close at all to optimal. // reduce = 2: the LLL algorithm is run on kernel(A); // this may be significantly slower than the other options, // but yields solutions that are provably close to optimal. // More precisely, if kernel(A) has rank k, // then the squared length of the obtained solution // is no more than max(1, 2^(k-2)) times that of // the optimal solution. This makes use of slight // variation of Babai's approximately nearest vector algorithm. // Of course, if the the rows of A are linearly independent, then // the value of reduce is irrelevant: the solution, if it exists, // is unique. // Note that regardless of the value of reduce, the algorithm // runs in polynomial time, and hence the bit-length of the solution // vector is bounded by a polynomial in the bit-length of the inputs. /**************************************************************************\ Floating Point Variants There are a number of floating point LLL variants available: you can choose the precision, the orthogonalization strategy, and the reduction condition. The wide variety of choices may seem a bit bewildering. See below the discussion "How to choose?". *** Precision: FP -- double QP -- quad_float (quasi quadruple precision) this is useful when roundoff errors can cause problems XD -- xdouble (extended exponent doubles) this is useful when numbers get too big RR -- RR (arbitrary precision floating point) this is useful for large precision and magnitudes Generally speaking, the choice FP will be the fastest, but may be prone to roundoff errors and/or overflow. *** Orthogonalization Strategy: -- Classical Gramm-Schmidt Orthogonalization. This choice uses classical methods for computing the Gramm-Schmidt othogonalization. It is fast but prone to stability problems. This strategy was first proposed by Schnorr and Euchner [C. P. Schnorr and M. Euchner, Proc. Fundamentals of Computation Theory, LNCS 529, pp. 68-85, 1991]. The version implemented here is substantially different, improving both stability and performance. -- Givens Orthogonalization. This is a bit slower, but generally much more stable, and is really the preferred orthogonalization strategy. For a nice description of this, see Chapter 5 of [G. Golub and C. van Loan, Matrix Computations, 3rd edition, Johns Hopkins Univ. Press, 1996]. *** Reduction Condition: -- LLL: the classical LLL reduction condition. -- BKZ: Block Korkin-Zolotarev reduction. This is slower, but yields a higher-quality basis, i.e., one with shorter vectors. See the Schnorr-Euchner paper for a description of this. This basically generalizes the LLL reduction condition from blocks of size 2 to blocks of larger size. ************* Calling Syntax for LLL routines *************** long [G_]LLL_{FP,QP,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta = 0.99, long deep = 0, LLLCheckFct check = 0, long verbose = 0); * The [ ... ] notation indicates something optional, and the { ... } indicates something that is chosen from among several alternatives. * The return value is the rank of B (but see below if check != 0). * The optional prefix G_ indicates that Givens rotations are to be used; otherwise, classical Gramm-Schmidt is used. * The choice FP, QP, XD, RR determines the precision used. * If the optional parameter U is given, then U is computed as the transition matrix: U * old_B = new_B * The optional argument "delta" is the reduction parameter, and may be set so that 0.50 <= delta < 1. Setting it close to 1 yields shorter vectors, and also improves the stability, but increases the running time. Recommended value: delta = 0.99. * The optional parameter "deep" can be set to any positive integer, which allows "deep insertions" of row k into row i, provided i <= deep or k-i <= deep. Larger values of deep will usually yield shorter vectors, but the running increases exponentially. NOTE: use of "deep" is obsolete, and has been "deprecated". It is recommended to use BKZ_FP to achieve higher-quality reductions. Moreover, the Givens versions do not support "deep", and setting deep != 0 will raise an error in this case. * The optional parameter "check" is a function that is invoked after each size reduction with the current row as an argument. If this function returns a non-zero value, the LLL procedure is immediately terminated. Note that it is possible that some linear dependencies remain undiscovered, so that the calculated rank value is in fact too large. In any case, zero rows discovered by the algorithm will be placed at the beginning, as usual. The check argument (if not zero) should be a routine taking a const vec_ZZ& as an argument and return value of type long. LLLCheckFct is defined via a typedef as: typedef long (*LLLCheckFct)(const vec_ZZ&); See the file subset.cpp for an example of the use of this feature. * The optional parameter "verbose" can be set to see all kinds of fun things printed while the routine is executing. A status report is printed every once in a while, and the current basis is optionally dumped to a file. The behavior can be controlled with these global variables: extern thread_local char *LLLDumpFile; // file to dump basis, 0 => no dump; // initially 0 extern thread_local double LLLStatusInterval; // seconds between status reports // initially 900s = 15min ************* Calling Syntax for BKZ routines *************** long [G_]BKZ_{FP,QP,QP1,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta=0.99, long BlockSize=10, long prune=0, LLLCheckFct check = 0, long verbose = 0); These functions are equivalent to the LLL routines above, except that Block Korkin-Zolotarev reduction is applied. We describe here only the differences in the calling syntax. * The optional parameter "BlockSize" specifies the size of the blocks in the reduction. High values yield shorter vectors, but the running time increases exponentially with BlockSize. BlockSize should be between 2 and the number of rows of B. * The optional parameter "prune" can be set to any positive number to invoke the Volume Heuristic from [Schnorr and Horner, Eurocrypt '95]. This can significantly reduce the running time, and hence allow much bigger block size, but the quality of the reduction is of course not as good in general. Higher values of prune mean better quality, and slower running time. When prune == 0, pruning is disabled. Recommended usage: for BlockSize >= 30, set 10 <= prune <= 15. * The QP1 variant uses quad_float precision to compute Gramm-Schmidt, but uses double precision in the search phase of the block reduction algorithm. This seems adequate for most purposes, and is faster than QP, which uses quad_float precision uniformly throughout. ******************** How to choose? ********************* I think it is safe to say that nobody really understands how the LLL algorithm works. The theoretical analyses are a long way from describing what "really" happens in practice. Choosing the best variant for a certain application ultimately is a matter of trial and error. The first thing to try is LLL_FP. It is the fastest of the routines, and is adequate for many applications. If there are precision problems, you will most likely get a warning message, something like "warning--relaxing reduction". If there are overflow problems, you should get an error message saying that the numbers are too big. If either of these happens, the next thing to try is G_LLL_FP, which uses the somewhat slower, but more stable, Givens rotations. This approach also has the nice property that the numbers remain smaller, so there is less chance of an overflow. If you are still having precision problems with G_LLL_FP, try LLL_QP or G_LLL_QP, which uses quadratic precision. If you are still having overflow problems, try LLL_XD or G_LLL_XD. I haven't yet come across a case where one *really* needs the extra precision available in the RR variants. All of the above discussion applies to the BKZ variants as well. In addition, if you have a matrix with really big entries, you might try using G_LLL_FP or LLL_XD first to reduce the sizes of the numbers, before running one of the BKZ variants. Also, one shouldn't rule out using the "all integer" LLL routines. For some highly structured matrices, this is not necessarily much worse than some of the floating point versions, and can under certain circumstances even be better. ******************** Implementation notes ********************* For all the floating point variants, I use a "relaxed" size reduction condition. Normally in LLL one makes all |\mu_{i,j}| <= 1/2. However, this can easily lead to infinite loops in floating point arithemetic. So I use the condition |\mu_{i,j}| <= 1/2 + fudge, where fudge is a very small number. Even with this, one can fall into an infinite loop. To handle this situation, I added some logic that detects, at quite low cost, when an infinite loop has been entered. When that happens, fudge is replaced by fudge*2, and a warning message "relaxing reduction condition" is printed. We may do this relaxation several times. If fudge gets too big, we give up and abort, except that LLL_FP and BKZ_FP make one last attempt to recover: they try to compute the Gramm-Schmidt coefficients using RR and continue. As described above, if you run into these problems, which you'll see in the error/warning messages, it is more effective to use the QP and/or Givens variants. For the Gramm-Schmidt orthogonalization, lots of "bookeeping" is done to avoid computing the same thing twice. For the Givens orthogonalization, we cannot do so many bookeeping tricks. Instead, we "cache" a certain amount of information, which allows us to avoid computing certain things over and over again. There are many other hacks and tricks to speed things up even further. For example, if the matrix elements are small enough to fit in double precision floating point, the algorithms avoid almost all big integer arithmetic. This is done in a dynamic, on-line fashion, so even if the numbers start out big, whenever they get small, we automatically switch to floating point arithmetic. \**************************************************************************/ /**************************************************************************\ Other Stuff \**************************************************************************/ void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c); // Computes Gramm-Schmidt data for B. Assumes B is an m x n matrix of // rank m. Let if { B^*(i) } is the othogonal basis, then c(i) = // |B^*(i)|^2, and B^*(i) = B(i) - \sum_{j=1}^{i-1} mu(i,j) B^*(j). void NearVector(vec_ZZ& w, const mat_ZZ& B, const vec_ZZ& a); // Computes a vector w that is an approximation to the closest vector // in the lattice spanned by B to a, using the "closest plane" // algorithm from [Babai, Combinatorica 6:1-13, 1986]. B must be a // square matrix, and it is assumed that B is already LLL or BKZ // reduced (the better the reduction the better the approximation). // Note that arithmetic in RR is used with the current value of // RR::precision(). // NOTE: Both of these routines use classical Gramm-Schmidt // orthogonalization. ntl-11.5.1/doc/RR.txt0000644417616742025610000004276714064716022016026 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: RR SUMMARY: The class RR is used to represent arbitrary-precision floating point numbers. The functions in this module guarantee very strong accuracy conditions which make it easy to reason about the behavior of programs using these functions. The arithmetic operations always round their results to p bits, where p is the current precision. The current precision can be changed using RR::SetPrecision(), and can be read using RR::precision(). The minimum precision that can be set is 53 bits. The maximum precision is limited only by the word size of the machine. A convenience class RRPush is provided to automatically save and restore the current precision. All arithmetic operations are implemented so that the effect is as if the result was computed exactly, and then rounded to p bits. If a number lies exactly half-way between two p-bit numbers, the "round to even" rule is used. So in particular, the computed result will have a relative error of at most 2^{-p}. The above rounding rules apply to all arithmetic operations in this module, except for the following routines: * The transcendental functions: log, exp, log10, expm1, log1p, pow, sin, cos, ComputePi * The power function * The input and ascii to RR conversion functions when using "e"-notation For these functions, a very strong accuracy condition is still guaranteed: the computed result has a relative error of less than 2^{-p + 1} (and actually much closer to 2^{-p}). That is, it is as if the resulted were computed exactly, and then rounded to one of the two neighboring p-bit numbers (but not necessarily the closest). The behavior of all functions in this module is completely platform independent: you should get *exactly* the same results on any platform (the only exception to this rule is the random number generator). Note that because precision is variable, a number may be computed with to a high precision p', and then be used as input to an arithmetic operation when the current precision is p < p'. The above accuracy guarantees still apply; in particular, no rounding is done until *after* the operation is performed. EXAMPLE: If x and y are computed to 200 bits of precision, and then the precision is set to 100 bits, then x-y will be computed correctly to 100 bits, even if, say, x and y agree in their high-order 50 bits. If x and y had been rounded to 100 bits before the subtraction, then the difference would only be accurate to 50 bits of precision. Note that the assignment operator and the copy constructor produce *exact* copies of their inputs---they are *never* rounded. This is a change in semantics from versions 2.0 and earlier in which assignment and copy rounded their outputs. This was deemed a design error and has been changed. If you want to force rounding to current precision, the easiest way to do this is with the RR to RR conversion routines: conv(x, a); or x = to_RR(a); This will round a to current precision and store the result in x. Note that writing x = a + 0; or x = a*1; also has the same effect. Unlike IEEE standard floating point, there are no "special values", like "infinity" or "not a number", nor are there any "denormalized numbers". Overflow, underflow, or taking a square root of a negative number all result in an error being raised. An RR is represented as a mantissa/exponent pair (x, e), where x is a ZZ and e is a long. The real number represented by (x, e) is x * 2^e. Zero is always represented as (0, 0). For all other numbers, x is always odd. CONVERSIONS AND PROMOTIONS: The complete set of conversion routines between RR and other types is documented in the file "conversions.txt". Conversion from any type to RR always rounds the result to the current precision. The basic operations also support the notion of "promotions", so that they promote a double to an RR. For example, one can write x = y + 1.5; where x and y are RR's. One should be aware that these promotions are always implemented using the double to RR conversion routine. SIZE INVARIANT: max(NumBits(x), |e|) < 2^(NTL_BITS_PER_LONG-4) \**************************************************************************/ #include #include #include class RR { public: RR(); // = 0 RR(const RR& a); // copy constructor explicit RR(double a); // promotion constructor RR& operator=(const RR& a); // assignment operator // NOTE: the copy constructor and assignment operator // produce exact copies of their inputs, and do not round // to current precision. RR& operator=(double a); // convert and assign ~RR(); // destructor RR(RR&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set RR& operator=(RR&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set const ZZ& mantissa() const; // read the mantissa long exponent() const; // read the exponent static void SetPrecision(long p); // set current precision to max(p, 53) bits. // The default is 150 static long precision(); // read current value of precision static void SetOutputPrecision(long p); // set the number of output decimal digits to max(p, 1). // The default is 10 static long OutputPrecision(); // read the current number of output decimal digits }; /**************************************************************************\ Comparison \**************************************************************************/ // standard comparison operators: long operator==(const RR& a, const RR& b); long operator!=(const RR& a, const RR& b); long operator<=(const RR& a, const RR& b); long operator>=(const RR& a, const RR& b); long operator <(const RR& a, const RR& b); long operator >(const RR& a, const RR& b); long IsZero(const RR& a); // test if 0 long IsOne(const RR& a); // test if 1 long sign(const RR& a); // returns sign of a (+1, -1, 0) long compare(const RR& a, const RR& b); // returns sign(a-b); // PROMOTIONS: operators ==, ..., > and function compare // promote double to RR on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: RR operator+(const RR& a, const RR& b); RR operator-(const RR& a, const RR& b); RR operator-(const RR& a); // unary - RR& operator+=(RR& x, const RR& a); RR& operator+=(RR& x, double a); RR& operator-=(RR& x, const RR& a); RR& operator-=(RR& x, double a); RR& operator++(RR& x); // prefix void operator++(RR& x, int); // postfix RR& operator--(RR& x); // prefix void operator--(RR& x, int); // postfix // procedural versions: void add(RR& z, const RR& a, const RR& b); // z = a+b void sub(RR& z, const RR& a, const RR& b); // z = a-b void negate(RR& z, const RR& a); // z = -a // PROMOTIONS: operators +, -, and procedures add, sub promote double // to RR on (a, b). void abs(RR& z, const RR& a); // z = |a| RR fabs(const RR& a); RR abs(const RR& a); /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: RR operator*(const RR& a, const RR& b); RR& operator*=(RR& x, const RR& a); RR& operator*=(RR& x, double a); // procedural versions: void mul(RR& z, const RR& a, const RR& b); // z = a*b void sqr(RR& z, const RR& a); // z = a * a RR sqr(const RR& a); // PROMOTIONS: operator * and procedure mul promote double to RR on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: RR operator/(const RR& a, const RR& b); RR& operator/=(RR& x, const RR& a); RR& operator/=(RR& x, double a); // procedural versions: void div(RR& z, const RR& a, const RR& b); z = a/b void inv(RR& z, const RR& a); // z = 1 / a RR inv(const RR& a); // PROMOTIONS: operator / and procedure div promote double to RR on (a, b). /**************************************************************************\ Transcendental functions \**************************************************************************/ void exp(RR& res, const RR& x); // e^x RR exp(const RR& x); void log(RR& res, const RR& x); // log(x) (natural log) RR log(const RR& x); void log10(RR& res, const RR& x); // log(x)/log(10) RR log10(const RR& x); void expm1(RR& res, const RR& x); RR expm1(const RR& x); // e^(x)-1; more accurate than exp(x)-1 when |x| is small void log1p(RR& res, const RR& x); RR log1p(const RR& x); // log(1 + x); more accurate than log(1 + x) when |x| is small void pow(RR& res, const RR& x, const RR& y); // x^y RR pow(const RR& x, const RR& y); void sin(RR& res, const RR& x); // sin(x); restriction: |x| < 2^1000 RR sin(const RR& x); void cos(RR& res, const RR& x); // cos(x); restriction: |x| < 2^1000 RR cos(const RR& x); void ComputePi(RR& pi); // approximate pi to current precision RR ComputePi_RR(); /**************************************************************************\ Rounding to integer values \**************************************************************************/ /*** RR output ***/ void trunc(RR& z, const RR& a); // z = a, truncated to 0 RR trunc(const RR& a); void floor(RR& z, const RR& a); // z = a, truncated to -infinity RR floor(const RR& a); void ceil(RR& z, const RR& a); // z = a, truncated to +infinity RR ceil(const RR& a); void round(RR& z, const RR& a); // z = a, truncated to nearest integer RR round(const RR& a); // ties are rounded to an even integer /*** ZZ output ***/ void TruncToZZ(ZZ& z, const RR& a); // z = a, truncated to 0 ZZ TruncToZZ(const RR& a); void FloorToZZ(ZZ& z, const RR& a); // z = a, truncated to -infinity ZZ FloorToZZ(const RR& a); // same as RR to ZZ conversion void CeilToZZ(ZZ& z, const RR& a); // z = a, truncated to +infinity ZZ CeilToZZ(const ZZ& a); void RoundToZZ(ZZ& z, const RR& a); // z = a, truncated to nearest integer ZZ RoundToZZ(const RR& a); // ties are rounded to an even integer // @anchor{push} /**************************************************************************\ Saving and restoring the current precision \**************************************************************************/ class RRPush { public: RRPush(); // saves the cuurent precision ~RRPush(); // restores the saved precision private: RRPush(const RRPush&); // disable void operator=(const RRPush&); // disable }; // Example: // // { // RRPush push; // don't forget to declare a variable!! // RR::SetPrecsion(new_p); // ... // } // old precsion restored when scope is exited class RROutputPush { public: RROutputPush(); // saves the cuurent output precision ~RROutputPush(); // restores the saved output precision private: RROutputPush(const RROutputPush&); // disable void operator=(const RROutputPush&); // disable }; // Example: // // { // RROutputPush push; // don't forget to declare a variable!! // RR::SetOutputPrecsion(new_op); // ... // } // old output precsion restored when scope is exited /**************************************************************************\ Miscelaneous \**************************************************************************/ void MakeRR(RR& z, const ZZ& a, long e); RR MakeRR(const ZZ& a, long e); // z = a*2^e, rounded to current precision void random(RR& z); RR random_RR(); // z = pseudo-random number in the range [0,1). // Note that the behaviour of this function is somewhat platform // dependent, because the underlying pseudo-ramdom generator is. void SqrRoot(RR& z, const RR& a); // z = sqrt(a); RR SqrRoot(const RR& a); RR sqrt(const RR& a); void power(RR& z, const RR& a, long e); // z = a^e, e may be negative RR power(const RR& a, long e); void power2(RR& z, long e); // z = 2^e, e may be negative RR power2_RR(long e); void clear(RR& z); // z = 0 void set(RR& z); // z = 1 void RR::swap(RR& a); void swap(RR& a, RR& b); // swap (pointer swap) /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine RR::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to RR::OutputPrecision(). \**************************************************************************/ ostream& operator<<(ostream& s, const RR& a); istream& operator>>(istream& s, RR& x); /**************************************************************************\ Specialized routines with explicit precision parameter These routines take an explicit precision parameter p. The value of p may be any positive integer. All results are computed to *precisely* p bits of precision, regardless of the current precision (as set by RR::SetPrecision). These routines are provided both for convenience and for situations where the computation must be done with a precision that may be less than 53. \**************************************************************************/ void AddPrec(RR& z, const RR& a, const RR& b, long p); // z = a + b RR AddPrec(const RR& a, const RR& b, long p); void SubPrec(RR& z, const RR& a, const RR& b, long p); // z = a - b RR SubPrec(const RR& a, const RR& b, long p); void NegatePrec(RR& z, const RR& a, long p); // z = -a RR NegatePrec(const RR& a, long p); void AbsPrec(RR& z, const RR& a, long p); // z = |a| RR AbsPrec(const RR& a, long p); void MulPrec(RR& z, const RR& a, const RR& b, long p); // z = a*b RR MulPrec(const RR& a, const RR& b, long p); void SqrPrec(RR& z, const RR& a, long p); // z = a*a RR SqrPrec(const RR& a, long p); void DivPrec(RR& z, const RR& a, const RR& b, long p); // z = a/b RR DivPrec(const RR& a, const RR& b, long p); void InvPrec(RR& z, const RR& a, long p); // z = 1/a RR DivPrec(const RR& a, long p); void SqrRootPrec(RR& z, const RR& a, long p); // z = sqrt(a) RR SqrRootPrec(const RR& a, long p); void TruncPrec(RR& z, const RR& a, long p); // z = a, truncated to 0 RR TruncPrec(const RR& a, long p); void FloorPrec(RR& z, const RR& a, long p); // z = a, truncated to -infinity RR FloorPrec(const RR& a, long p); void CeilPrec(RR& z, const RR& a, long p); // z = a, truncated to +infinity RR CeilPrec(const RR& a, long p); void RoundPrec(RR& z, const RR& a, long p); // z = a, // truncated to nearest integer, // ties are roundec to an even // integer RR RoundPrec(const RR& a, long p); void ConvPrec(RR& z, const RR& a, long p); // z = a RR ConvPrec(const RR& a, long p); void ConvPrec(RR& z, const ZZ& a, long p); // z = a RR ConvPrec(const ZZ& a, long p); void ConvPrec(RR& z, long a, long p); // z = a RR ConvPrec(long a, long p); void ConvPrec(RR& z, int a, long p); // z = a RR ConvPrec(int a, long p); void ConvPrec(RR& z, unsigned long a, long p); // z = a RR ConvPrec(unsigned long a, long p); void ConvPrec(RR& z, unsigned int a, long p); // z = a RR ConvPrec(unsigned int a, long p); void ConvPrec(RR& z, double a, long p); // z = a RR ConvPrec(double a, long p); void ConvPrec(RR& z, const xdouble& a, long p); // z = a RR ConvPrec(const xdouble& a, long p); void ConvPrec(RR& z, const quad_float& a, long p); // z = a RR ConvPrec(const quad_float& a, long p); void ConvPrec(RR& z, const char *s, long p); // read z from s RR ConvPrec(const char *s, long p); istream& InputPrec(RR& z, istream& s, long p); // read z from s RR InputPrec(istream& s, long p); // The functional variant raises an error if input // is missing or ill-formed, while procedural form // does not. void MakeRRPrec(RR& z, const ZZ& a, long e, long p); // z = a*2^e RR MakeRRPrec(const ZZ& a, long e, long p); /**************************************************************************\ COMPATABILITY NOTES: (1) Prior to version 5.3, the documentation indicated that under certain circumstances, the value of the current precision could be directly set by setting the variable RR::prec. Such usage is now considered obsolete. To perform computations using a precision of less than 53 bits, users should use the specialized routines AddPrec, SubPrec, etc., documented above. (2) The routine RoundToPrecision is obsolete, although for backward compatability, it is still declared (in both procedural and function forms), and is equivalent to ConvPrec. (3) In versions 2.0 and earlier, the assignment operator and copy constructor for the class RR rounded their outputs to the current precision. This is no longer the case: their outputs are now exact copies of their inputs, regardless of the current precision. \**************************************************************************/ ntl-11.5.1/doc/SmartPtr.txt0000644417616742025610000007155714064716022017256 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************** SmartPtr: a smart pointer class. Synopsis: provides a reference counted smart pointer, similar to shared_ptr in the standard library. It is provided here to minimize reliance on the standard library, especially for older C++ compilers, which may not provide shared_ptr, or it may be in TR1, which gets messy. Examples: SmartPtr p1; // initialize to null SmartPtr p1(0); SmartPtr p2 = 0; // 0/nullptr implicitly converts to SmartPtr SmartPtr p3(p1); // copy constructor T *rp; SmartPtr p4(rp); // construct using raw pointer (explicit): better // to use MakeSmart below p1 = MakeSmart(...); // build new T object by invoking constructor // T(...) with pseudo-variadic templates. // This is safer and more efficient that // using the raw-pointer constructor p1 = p2; // assignment p1 = 0; // assign null if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for not null ... if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) *p1 // dereferencing p1->... p1.get(); // return the underlying raw pointer...dangerous! p1.swap(p2); // fast swap swap(p1, p2); Automatic Conversions: If S is another class, SmartPtr converts to SmartPtr if S* converts to T* (for example, if S is a subclass of T). Similarly, SmartPtr and SmartPtr may be compared if S* and T* may be compared. 0/nullptr automatically converts to SmartPtr. MakeSmart: One can write SmartPtr p = MakeSmart(x1, ..., xn), and this will create a smart pointer to an object constructed as T(x1, ..., xn). Besides notational convenience, it also reduces the number of memory allocations from 2 to 1, as the data and control block can be allocated in one chunck of memory. In C++11 mode, this is implemented using variadic templates and "perfect forwarding". Otherwise, this is implemented using macros, and there are some limitations: first, the number n of arguments is limited to 9; second, all arguments are pass by const reference, but you can work around this by using the helper function Fwd. For example, if T has a 2-argument constructor where the second must be a non-const reference of some type, and x2 is a variable of that type, you can write MakeSmart(x1, Fwd(x2)), to forward that reference through in a typesafe manner. Note that for compatibility, the Fwd function is also available in C++11 mode, so you can write code that will work in either mode. MakeRaw: One can also write T *p = MakeRaw(x1, ..., xn) to create a raw pointer. This is the same as writing T *p = new T(x1, ..., xn), except that error handling is determined by the NTL_EXCEPTION flag (on => bad_alloc exception is thrown, off => error message and abort). MakeRawArray: Another utility routine: one can write T *p = MakeRawArray(n) to make a plain array of n T objects. Error handling is the same as for MakeRaw. Dynamic casting: I've also supplied a dynamic cast operation for smart pointers. SmartPtr d = MakeSmart(); // d points to Derived SmartPtr b = d; // implicit upcast: OK SmartPtr d1 = DynamicCast(b); // downcast to a Derived object -- returns null for a bad cast DeleterPolicy: Normally, when the object pointed to a SmartPtr needs to be destroyed, this is done by invoking delete on the raw pointer. The user can override this behavior by specifying a "deleter policy", which is a class P that defines a static member function deleter, which is invoked as P::deleter(p). Such a policy can be attached to a SmartPtr using a specialized constructor (see below). A deleter policy can be useful, for example, in realizing the PIPL pattern, where the class T's definition is not visible. The specified deleter can invoke a free-standing function that itself invokes delete. A deleter policy can also be useful is memory is to be managed using some mechanism other than new/delete. Implementation notes: If NTL is compiled with the NTL_THREADS option, then the reference counting will be thread safe. The SmartPtrControl class heirarchy is used to make sure the right destructor is called when the ref count goes to zero. This can be an issue for forward declared classes and for subclasses. For example, if T is forward declared in a context where the ref count goes to zero, or if the object's actual type is a subclass of T and T's destructor was not declared virtual. The implementation of SmartPtr guarantees correct behavior in these situations. The null tests p, !p, p == 0, are all effected via an implicit conversion from SmartPtr to a funny pointer type (a pointer to a member function, which avoids other, unwanted implicit conversions: this is the so-called "safe bool idiom"); Also, there is an implicit conversion from another funny pointer type to SmartPtr, which is how the implicit conversion from 0/nullptr is achieved. In C++11 both of the above effects could perhaps be achieved more directly. The new "explict bool" operator can replace the "safe bool idiom", and the new nullptr_t type could be used to get the conversion from null to work. NOTES: See http://www.artima.com/cppsource/safebool.html for more on the "safe bool idiom". *****************************************************************************/ // The default "deleter policy" struct DefaultDeleterPolicy { template static void deleter(T *p) { delete p; } }; // A tagging class, for better readability in invoking constructor. // Usage: SmartPtr p(r, ChoosePolicy()); template struct ChoosePolicy { }; template class SmartPtr { public: public: template explicit SmartPtr(Y* p); // construct smart pointer from raw pointer with deleter policy // DefaultDeleterPolicy (so p should be allocated using new). // NOTE: Y* must convert to T*, but upon the original pointer is preserved // so that when ref count drops to 0, the *original* object of type Y is destroyed. // EXCEPTIONS: a control block is dynamically allocated; // if this allocation fails, the object pointed to by p is destroyed // and a bad_alloc exception is thrown template SmartPtr(Y* p, ChoosePolicy

); // construct smart pointer from raw pointer with deleter policy P. // NOTE: Y* must convert to T*, but upon the original pointer is preserved // so that when ref count drops to 0, the *original* object of type Y is destroyed. // EXCEPTIONS: a control block is dynamically allocated; // if this allocation fails, the object pointed to by p is destroyed // and a bad_alloc exception is thrown SmartPtr(); // initial value null SmartPtr(fake_null_type1); // automatic conversion from 0/nullptr ~SmartPtr(); // destructor SmartPtr(const SmartPtr& other); SmartPtr& operator=(const SmartPtr& other); // copy and assignment template SmartPtr(const SmartPtr& other); template SmartPtr& operator=(const SmartPtr& other); // copy and assignment SmartPtr(SmartPtr&& other) noexcept; SmartPtr& operator=(SmartPtr&& other) noexcept; // move semantics (C++11 only) template SmartPtr(SmartPtr&& other) noexcept; template SmartPtr& operator=(SmartPtr&& other); // move semantics (C++11 only) T& operator*() const; T* operator->() const; // indirection T* get() const; // get underlying raw pointer void swap(SmartPtr& other); SmartPtr(fake_null_type); // allows assignment and initialization from 0 operator fake_null_type() const; // allows comparisons to 0 template SmartPtr DynamicCast() const; }; // free swap function template void swap(SmartPtr& p, SmartPtr& q); // free dynamic cast function template SmartPtr DynamicCast(const SmartPtr& p); // Equality testing template bool operator==(const SmartPtr& a, const SmartPtr& b); template bool operator!=(const SmartPtr& a, const SmartPtr& b); // MakeSmart variadic template template SmartPtr MakeSmart(Args&&... args); // EXCEPTIONS: may throw an exception if constructor for T throws // or memory allocation fails // EXCEPTIONS: unless otherwise specified, the methods above // never throw an exception (under C++11 rules, if a destructor // is invoked that throws an exception, the program will terminate). /**************************************************************************** Experimantal: CloneablePtr ...essentially same interface as SmartPtr, but allows cloning of complete objects. The differences: * must construct using MakeCloneable * a clone method is provided * implicit conversion from CloneablePtr to SmartPtr is allowed Example: CloneablePtr d = MakeCloneable(); // d points to Derived CloneablePtr b = d; // implicit upcast: OK CloneablePtr b1 = b.clone(); // clone of b, which is really a Derived object CloneablePtr d1 = DynamicCast(b1); // downcast to a Derived object -- returns null for a bad cast SmartPtr b2 = d1; Implementation: In the clone method, the object is constructed using the copy constructor for the type T, where T is the compile-time type with which the first smart pointer to this object was was created, even if the pointer has been subsequently upcasted to a base type S. Such objects must have been initially created using the MakeCloneable function. It turns out, this is hard to do in a completely standards-compliant way, because of the type erasure going on. So I settled on the current method, which does some low-level pointer arithmetic. Even with fancy things like multiple and virtual inheritance, it should work, under the assumption that if two objects have the same (runtime) type, then their memory layout is the same. I don't think anything like that is guaranteed by the standard, but this seems reasonable, and it seems to work. Like I said, it is experimental, and I would appreciate feedback from C++ gurus. Note that NTL does not use this feature, but I do have applications where this is convenient. **********************************************************************************/ template class CloneablePtr { public: CloneablePtr(); // initial value null ~CloneablePtr(); // if ref count drops to zero, then delete referent CloneablePtr(const CloneablePtr& other); CloneablePtr& operator=(const CloneablePtr& other); // copy and assignment template CloneablePtr(const CloneablePtr& other); template CloneablePtr& operator=(const CloneablePtr& other); // copy and assignment CloneablePtr(CloneablePtr&& other) noexcept; CloneablePtr& operator=(CloneablePtr&& other) noexcept; // move semantics (C++11 only) template CloneablePtr(CloneablePtr&& other) noexcept; template CloneablePtr& operator=(CloneablePtr&& other); // move semantics (C++11 only) T& operator*() const; T* operator->() const; // indirection T* get() const; // get underlying raw pointer void swap(CloneablePtr& other); CloneablePtr(fake_null_type); // allows assignment and initialization from 0 operator fake_null_type() const; // allows comparisons to 0 template CloneablePtr DynamicCast() const; CloneablePtr clone() const; // construct a clone, using the copy constructor // EXCEPTIONS: may throw if copy construction fails template operator SmartPtr(); // implicit conversion from CloneablePtr to SmartPtr, // allowed if T* converts implicitly to Y*. }; // free swap function template void swap(CloneablePtr& p, CloneablePtr& q); // free dynamic cast function template CloneablePtr DynamicCast(const CloneablePtr& p); // Equality testing template bool operator==(const CloneablePtr& a, const CloneablePtr& b); template bool operator!=(const CloneablePtr& a, const CloneablePtr& b); // MakeCloneable psuedo-variadic template template CloneablePtr MakeCloneable(Args&&... args); // EXCEPTIONS: may throw an exception if constructor for T throws // or memory allocation fails // EXCEPTIONS: unless otherwise specified, the methods above // never throw an exception (under C++11 rules, if a destructor // is invoked that throws an exception, the program will terminate). /********************************************************************** UniquePtr -- unique pointer to object with copying disabled. Useful for pointers inside classes so that we can automatically destruct them. Constructors: UniquePtr p1; // initialize with null UniquePtr p1(0); T* rp; UniquePtr p1(rp); // construct using raw pointer (explicit) p1 = 0; // destroy's p1's referent and assigns null p1.make(...); // destroy's p1's referent and assigns // a fresh objected constructed via T(...), // using psuedo-variadic templates p1.reset(rp); // destroy's p1's referent and assign rp if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... *p1 // dereferencing p1->... rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to null p1.move(p2); // move p2 to p1, destroying p1's referent // if p1 != p2 p1.swap(p2); // swap pointers swap(p1, p2); DeleterPolicy: UniquePtr supports a "deleter policy", analogous to that used in SmartPtr. Normally, when the object pointed to a UniquePtr needs to be destroyed, this is done by invoking delete on the raw pointer. The user can override this behavior by specifying a "deleter policy", which is a class P that defines a static member function deleter, which is invoked as P::deleter(p). Unlike with a SmartPtr, the deleter policy must be attached to the type. The default policy is the same DefaultDeleterPolicy, defined above. A deleter policy can be useful, for example, in realizing the PIPL pattern, where the class T's definition is not visible. The specified deleter can invoke a free-standing function that itself invokes delete. A deleter policy can also be useful is memory is to be managed using some mechanism other than new/delete. **********************************************************************/ template class UniquePtr { public: explicit UniquePtr(T *p); // construct UniquePtr from raw pointer (allocated with new) UniquePtr(); // initial value is null UniquePtr(UniquePtr&& other) noexcept; UniquePtr& operator=(UniquePtr&& other) noexcept; // move semantics (C++11 only) UniquePtr& operator=(fake_null_type1); // allows assignment of 0; equivalent to calling reset() ~UniquePtr(); // destroys referent by calling P::deleter void reset(T* p = 0); // reset underlying pointer to p, destroying original referent // by calling P::deleter template void make(Args&&... args); // pseudo-variadic template, roughly equivalent to // reset(new T(std::forward args...)) // EXCEPTIONS: this may throw (but provides strong ES guarantee) T& operator*() const; T* operator->() const; // indirection T* get() const; // get raw pointer T* release(); // returns raw pointer, and sets the raw pointer to null void move(UniquePtr& other); // move other to *this, destroying original referent // by calling P::deleter void swap(UniquePtr& other); // swap raw pointers operator fake_null_type() const; // allows comparison with 0 private: UniquePtr(const UniquePtr&); // disabled void operator=(const UniquePtr&); // disabled }; // free swap function template void swap(UniquePtr& p, UniquePtr& q); // Equality testing template bool operator==(const UniquePtr& a, const UniquePtr& b); template bool operator!=(const UniquePtr& a, const UniquePtr& b); // EXCEPTIONS: unless otherwise specified, the methods above // never throw an exception (under C++11 rules, if a destructor // is invoked that throws an exception, the program will terminate). /********************************************************************** CopiedPtr -- essentially the same interface and implemetation as UniquePtr, with the following exceptions: * copy constructor is defined: by default, it will create a copy of the referrent using T's copy constructor (but this bahavior can be overridden -- see below) * assignment operator is defined (and implemented in terms of the copy constructor) * The policy managing a CopiedPtr specifier deleter and copier functions: the deleter is used to delete objects and the copies is used for making copies (see below). NOTE: this class is meant to replace the OptionalVal class, whose interface is not so nice. For backwards compatibility, OptionalVal will be maintained, however. **********************************************************************/ // This class specifies the default copier struct DefaultCopierPolicy { template static T* copier(T *p) { return (p ? MakeRaw(*p) : 0); } }; // This class specifies an alternative copier, which is meant // to perform "deep" copies on class heirarchies that support an // appropriate clone() method. struct CloningCopier { template static T* copier(T *p) { return (p ? p->clone() : 0); } }; struct DefaultCopiedPtrPolicy : DefaultDeleterPolicy, DefaultCopierPolicy { }; struct CloningCopiedPtrPolicy : DefaultDeleterPolicy, CloningCopier { }; template class CopiedPtr { public: explicit CopiedPtr(T *p); // construct CopiedPtr from raw pointer (allocated with new) CopiedPtr(); // initial value is null CopiedPtr(const CopiedPtr& other); // creates a copy of other's referent by calling P::copier void operator=(const CopiedPtr&); // creates a copy of other's referent by calling P::copier, // and destroys original referent by calling P::deleter CopiedPtr& operator=(fake_null_type1); // allows assignment of 0; equivalent to calling reset() ~CopiedPtr(); // destroys referent by calling P::deleter CopiedPtr(CopiedPtr&& other) noexcept; CopiedPtr& operator=(CopiedPtr&& other) noexcept; // move semantics (C++11 only) void reset(T* p = 0); // reset underlying pointer to p, destroying original referent // by calling P::deleter template void make(Args&&... args); // pseudo-variadic template, roughly equivalent to // reset(new T(std::forward args...)) // EXCEPTIONS: this may throw (but provides strong ES guarantee) T& operator*() const; T* operator->() const; // indirection T* get() const; // get raw pointer T* release(); // returns raw pointer, and sets the raw pointer to null void move(CopiedPtr& other); // move other to *this, destroying original referent // by calling P::deleter void swap(CopiedPtr& other); // swap raw pointers operator fake_null_type() const; // allows comparison with 0 }; // free swap function template void swap(CopiedPtr& p, CopiedPtr& q); // Equality testing template bool operator==(const CopiedPtr& a, const CopiedPtr& b); template bool operator!=(const CopiedPtr& a, const CopiedPtr& b); // EXCEPTIONS: unless otherwise specified, the methods above // never throw an exception (under C++11 rules, if a destructor // is invoked that throws an exception, the program will terminate). /********************************************************************** UniqueArray -- similar to UniquePtr, but for arrays. These arrays cannot be resized -- for that, you should use the Vec class. Constructors: UniqueArray p1; // initialize with null UniqueArray p1(0); T* rp; UniqueArray p1(rp); // construct using raw pointer (explicit) p1 = 0; // destroy's p1's referent and assigns null p1.SetLength(n); // destroy's p1's referent and assigns // a fresh objected constructed via new T[n] p1.reset(rp); // destroy's p1's referent and assign rp if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... p1[i] // array indexing rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to null p1.move(p2); // move p2 to p1, destroying p1's referent // if p1 != p2 p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class UniqueArray { public: explicit UniqueArray(T *p); // construct from raw pointer (allocated with new[]) UniqueArray(); // initially null UniqueArray& operator=(fake_null_type1); // allows of 0 ~UniqueArray(); UniqueArray(UniqueArray&& other) noexcept; UniqueArray& operator=(UniqueArray&& other) noexcept; // move semantics (C++11 only) void reset(T* p = 0); // reset with raw pointer, destroying referent void SetLength(long n); // destroys referent and allocates an array of size n // EXCEPTIONS: this may throw (but provides strong ES guarantee) T& operator[](long i) const; // accesses ith element in the array (currently no range checking) T* get() const; // get raw pointer T* elts() const; // get raw pointer (for compatibility with the Vec class) T* release(); // get raw pointer and reset to null void move(UniqueArray& other); // move raw pointer void swap(UniqueArray& other); // swap raw pointer operator fake_null_type() const; // allows comparison to 0 private: UniqueArray(const UniqueArray&); // disabled void operator=(const UniqueArray&); // disabled }; // free swap function template void swap(UniqueArray& p, UniqueArray& q); // Equality testing template bool operator==(const UniqueArray& a, const UniqueArray& b); template bool operator!=(const UniqueArray& a, const UniqueArray& b); /********************************************************************** Unique2DArray -- unique pointer to array of arrays. This is very similar to UniqueArray< UniqueArray >, except that we can retrofit old code that accepts objects of type T**. Constructors: Unique2DArray p1; // initialize with null Unique2DArray p1(0); p1 = 0; // destroy's p1's referent and assigns null p1.reset(); p1.SetLength(n); // destroy's p1's referent and assigns // a fresh array of null pointers p1.SetDims(n, m) // creates an n x m array if (!p1) ... // test for null if (p1 == 0) ... if (p1) ... // test for nonnull if (p1 != 0) ... if (p1 == p2) ... // test for equality if (p1 != p2) ... p1[i] // array indexing T **rp; rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to null p1.move(p2); // if p1 != p2 then: // makes p1 point to p2's referent, // setting p2 to null and destroying // p1's referent p1.swap(p2); // fast swap swap(p1, p2); **********************************************************************/ template class Unique2DArray { public: typedef T *T_ptr; Unique2DArray(); // initially null Unique2DArray& operator=(fake_null_type1); // allows initialization and assignment of 0 ~Unique2DArray(); // destroys the entire array and each row in the array Unique2DArray(Unique2DArray&& other) noexcept; Unique2DArray& operator=(Unique2DArray&& other) noexcept; // move semantics (C++11 only) void reset(); // reset to null void SetLength(long n); // resets the array to a vector of length n, // each entry initialized to null. // EXCEPTIONS: may throw (provides strong ES guarantee) void SetDims(long n, long m); // resets the array to a 2D array with n rows and m columns. // EXCEPTIONS: may throw (provides strong ES guarantee) void SetDimsFrom1(long n, long m); // same as above, but only initializes rows 1..n-1. // this helps with some legacy code. // EXCEPTIONS: may throw (provides strong ES guarantee) T_ptr& operator[](long i) const; // array indexing, no range checking T_ptr* get() const; // return underlying pointer T_ptr* release() { len = 0; return dp.release(); } // return underlying pointer and reset to null void move(Unique2DArray& other); // move pointers void swap(Unique2DArray& other); // swap pointers operator fake_null_type() const; // allows comparison to 0 private: Unique2DArray(const Unique2DArray&); // disabled void operator=(const Unique2DArray&); // disabled }; // free swap function template void swap(Unique2DArray& p, Unique2DArray& q); // Equality testing template bool operator==(const Unique2DArray& a, const Unique2DArray& b); template bool operator!=(const Unique2DArray& a, const Unique2DArray& b); /********************************************************************** OptionalVal -- unique pointer to object with copying enabled. NOTE: this class is deprecated; use CopiedPtr instead. It will, however, be maintained indefinitely for backward compatibility. Constructors: OptionalVal p1; // initialize with null T* rp; OptionalVal p1(rp); // construct using raw pointer (explicit) OptionalVal p2(p1); // construct a copy of p1's referent p1.make(...); // destroy's p1's referent and assigns // a fresh objected constructed via T(...), // using psuedo variadic templates p1.reset(rp); // destroy's p1's referent and assign rp if (p1.exists()) ... // test for null p1.val() // dereference rp = p1.get(); // fetch raw pointer rp = p1.release(); // fetch raw pointer, and set to NULL p1.move(p2); // move p2 to p1, destroying p1's referent // if p1 != p2 p1 = p2; // deep copy, using T's copy constructor p1.swap(p2); // swap pointers swap(p1, p2); **********************************************************************/ template class OptionalVal { public: explicit OptionalVal(T *p); // initialize using raw pointer (allocated with new) OptionalVal(); // initialize to null OptionalVal(const OptionalVal& other); // initialize using a deep copy (via T's copy constructor) OptionalVal& operator=(const OptionalVal& other); // assignment using a deep copy (via T's copy constructor) ~OptionalVal(); // destroys the referent OptionalVal(OptionalVal&& other) noexcept; OptionalVal& operator=(OptionalVal&& other) noexcept; // move semantics (C++11 only) void reset(T* p = 0); // resets the referent template void make(Args&&... args); // pseudo-variadic template. // resets the referent to a new object T(std::forward args...) // EXCEPTIONS: may throw an exception (but provides strong ES guarantee) T& val() const; // returns reference to referent // if underlying pointer p is null, the indirection *p // is undefined behavior, but most likely leads to program termination bool exists() const; // checks that underlying pointer is not null T* get() const; // returns underlying raw pointer T* release(); // returns raw pointer, and sets the raw pointer to null void move(OptionalVal& other); // performs a (shallow) pointer move void swap(OptionalVal& other); // performs a (shallow) pointer swap }; // free swap function template void swap(OptionalVal& p, OptionalVal& q); // EXCEPTIONS: unless otherwise specified, the methods above // never throw an exception (under C++11 rules, if a destructor // is invoked that throws an exception, the program will terminate). ntl-11.5.1/doc/ZZ.txt0000644417616742025610000010672214064716022016036 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ SUMMARY: The class ZZ is used to represent signed, arbitrary length integers. Routines are provided for all of the basic arithmetic operations, as well as for some more advanced operations such as primality testing. Space is automatically managed by the constructors and destructors. This module also provides routines for generating small primes, and fast routines for performing modular arithmetic on single-precision numbers. \**************************************************************************/ #include class ZZ { public: ZZ(); // initial value is 0 ZZ(const ZZ& a); // copy constructor explicit ZZ(long a); // promotion constructor ~ZZ(); // destructor ZZ& operator=(const ZZ& a); // assignment operator ZZ& operator=(long a); ZZ(ZZ&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set ZZ& operator=(ZZ&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set // typedefs to aid in generic programming typedef ZZ_p residue_type; typedef ZZX poly_type; // ... }; // NOTE: A ZZ is represented as a sequence of "limbs", // where each limb is between 0 and 2^{NTL_ZZ_NBITS-1}. // NTL_ZZ_NBITS is macros defined in . // SIZE INVARIANT: the number of bits in a ZZ is always less than // 2^(NTL_BITS_PER_LONG-4). /**************************************************************************\ Comparison \**************************************************************************/ // The usual comparison operators: long operator==(const ZZ& a, const ZZ& b); long operator!=(const ZZ& a, const ZZ& b); long operator<(const ZZ& a, const ZZ& b); long operator>(const ZZ& a, const ZZ& b); long operator<=(const ZZ& a, const ZZ& b); long operator>=(const ZZ& a, const ZZ& b); // other stuff: long sign(const ZZ& a); // returns sign of a (-1, 0, +1) long IsZero(const ZZ& a); // test for 0 long IsOne(const ZZ& a); // test for 1 long compare(const ZZ& a, const ZZ& b); // returns sign of a-b (-1, 0, or 1). // PROMOTIONS: the comparison operators and the function compare // support promotion from long to ZZ on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ operator+(const ZZ& a, const ZZ& b); ZZ operator-(const ZZ& a, const ZZ& b); ZZ operator-(const ZZ& a); // unary - ZZ& operator+=(ZZ& x, const ZZ& a); ZZ& operator+=(ZZ& x, long a); ZZ& operator-=(ZZ& x, const ZZ& a); ZZ& operator-=(ZZ& x, long a); ZZ& operator++(ZZ& x); // prefix void operator++(ZZ& x, int); // postfix ZZ& operator--(ZZ& x); // prefix void operator--(ZZ& x, int); // postfix // procedural versions: void add(ZZ& x, const ZZ& a, const ZZ& b); // x = a + b void sub(ZZ& x, const ZZ& a, const ZZ& b); // x = a - b void SubPos(ZZ& x, const ZZ& a, const ZZ& b); // x = a-b; assumes a >= b >= 0. void negate(ZZ& x, const ZZ& a); // x = -a void abs(ZZ& x, const ZZ& a); // x = |a| ZZ abs(const ZZ& a); // PROMOTIONS: binary +, -, as well as the procedural versions add, sub // support promotions from long to ZZ on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ operator*(const ZZ& a, const ZZ& b); ZZ& operator*=(ZZ& x, const ZZ& a); ZZ& operator*=(ZZ& x, long a); // procedural versions: void mul(ZZ& x, const ZZ& a, const ZZ& b); // x = a * b void sqr(ZZ& x, const ZZ& a); // x = a*a ZZ sqr(const ZZ& a); // PROMOTIONS: operator * and procedure mul support promotion // from long to ZZ on (a, b). /**************************************************************************\ Combined Multiply and Add \**************************************************************************/ void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b); // x += a*b void MulAddTo(ZZ& x, const ZZ& a, long b); // x += a*b void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b); // x -= a*b void MulSubFrom(ZZ& x, const ZZ& a, long b); // x -= a*b // NOTE: these are provided for both convenience and efficiency. // The single-precision versions may be significantly // faster than the code sequence // mul(tmp, a, b); add(x, x, tmp); // However, for the single-precision version, the use-case // that is optimized is for |b| < 2^{NTL_WSP_BOUND}. /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ operator/(const ZZ& a, const ZZ& b); ZZ operator/(const ZZ& a, long b); ZZ operator%(const ZZ& a, const ZZ& b); long operator%(const ZZ& a, long b); ZZ& operator/=(ZZ& x, const ZZ& b); ZZ& operator/=(ZZ& x, long b); ZZ& operator%=(ZZ& x, const ZZ& b); // procedural versions: void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b); // q = floor(a/b), r = a - b*q. // This implies that: // |r| < |b|, and if r != 0, sign(r) = sign(b) void div(ZZ& q, const ZZ& a, const ZZ& b); // q = floor(a/b) void rem(ZZ& r, const ZZ& a, const ZZ& b); // q = floor(a/b), r = a - b*q // single-precision variants: long DivRem(ZZ& q, const ZZ& a, long b); // q = floor(a/b), r = a - b*q, return value is r. long rem(const ZZ& a, long b); // q = floor(a/b), r = a - b*q, return value is r. // divisibility testing: long divide(ZZ& q, const ZZ& a, const ZZ& b); long divide(ZZ& q, const ZZ& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0. long divide(const ZZ& a, const ZZ& b); long divide(const ZZ& a, long b); // if b | a, returns 1; otherwise returns 0. /**************************************************************************\ GCD's \**************************************************************************/ void GCD(ZZ& d, const ZZ& a, const ZZ& b); ZZ GCD(const ZZ& a, const ZZ& b); // d = gcd(a, b) (which is always non-negative). Uses a binary GCD // algorithm. void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b); // d = gcd(a, b) = a*s + b*t. // The coefficients s and t are defined according to the standard // Euclidean algorithm applied to |a| and |b|, with the signs then // adjusted according to the signs of a and b. // The implementation may or may not Euclid's algorithm, // but the coefficients s and t are always computed as if // it did. // In particular, the following inequalties should hold: // |s| <= 1 OR |s| < |b|/(2*d) // |t| <= 1 OR |t| < |a|/(2*d) // special-purpose single-precision variants: long GCD(long a, long b); // return value is gcd(a, b) (which is always non-negative) void XGCD(long& d, long& s, long& t, long a, long b); // d = gcd(a, b) = a*s + b*t. // The coefficients s and t are defined according to the standard // Euclidean algorithm applied to |a| and |b|, with the signs then // adjusted according to the signs of a and b. /**************************************************************************\ Modular Arithmetic The following routines perform arithmetic mod n, where n > 1. All arguments (other than exponents) are assumed to be in the range 0..n-1. Some routines may check this and raise an error if this does not hold. Others may not, and the behaviour is unpredictable in this case. \**************************************************************************/ void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a+b)%n ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n); void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a-b)%n ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n); void NegateMod(ZZ& x, const ZZ& a, const ZZ& n); // x = -a % n ZZ NegateMod(const ZZ& a, const ZZ& n); void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a*b)%n ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n); void SqrMod(ZZ& x, const ZZ& a, const ZZ& n); // x = a^2 % n ZZ SqrMod(const ZZ& a, const ZZ& n); void InvMod(ZZ& x, const ZZ& a, const ZZ& n); ZZ InvMod(const ZZ& a, const ZZ& n); // x = a^{-1} mod n (0 <= x < n); error is raised occurs if inverse // not defined // If exceptions are enabled, an object of the following class // is throw by the InvMod routine if the inverse of a mod n is // not defined. The methods get_a() and get_n() give read-only // access to the offending values of a and n. // This also happens for any indirect call to InvMod, via PowerMod, // of via inverse computations in ZZ_p. class InvModErrorObject : public ArithmeticErrorObject { public: InvModErrorObject(const char *s, const ZZ& a, const ZZ& n); const ZZ& get_a() const; const ZZ& get_n() const; }; long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n); // if gcd(a,n) = 1, then return-value = 0, x = a^{-1} mod n; // otherwise, return-value = 1, x = gcd(a, n) void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n); ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n); void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n); ZZ PowerMod(const ZZ& a, long e, const ZZ& n); // x = a^e % n (e may be negative) // PROMOTIONS: AddMod, SubMod, and MulMod (both procedural and functional // forms) support promotions from long to ZZ on (a, b). // @anchor{modarith} /**************************************************************************\ Single-precision modular arithmetic These routines implement single-precision modular arithmetic. If n is the modulus, all inputs should be in the range 0..n-1. The number n itself should be in the range 2..NTL_SP_BOUND-1. Most of these routines are, of course, implemented as fast inline functions. No checking is done that inputs are in range. \**************************************************************************/ long AddMod(long a, long b, long n); // return (a+b)%n long SubMod(long a, long b, long n); // return (a-b)%n long NegateMod(long a, long n); // return (-a)%n long MulMod(long a, long b, long n); // return (a*b)%n long MulMod(long a, long b, long n, mulmod_t ninv); // return (a*b)%n. // // Usually faster than plain MulMod when n is fixed for many // invocations. The value ninv should be precomputed as // mulmod_t ninv = PrepMulMod(n); mulmod_t PrepMulMod(long n); // Prepare auxiliary data for MulMod. long MulModPrecon(long a, long b, long n, mulmod_precon_t bninv); // return (a*b)%n. // // Usually much faster than MulMod when both b and n are fixed for // many invocations. The value bninv should be precomputed as // mulmod_precon_t bninv = PrepMulModPrecon(b, n); // or as // mulmod_precon_t bninv = PrepMulModPrecon(b, n, ninv); // where ninv = PrepMulMod(n). mulmod_precon_t PrepMulModPrecon(long b, long n); mulmod_precon_t PrepMulModPrecon(long b, long n, mulmod_t ninv); // Prepare auxiliary data for MulModPrecon. // In the second version, ninv = PrepMulMod(n). long InvMod(long a, long n); // computes a^{-1} mod n. Error is raised if undefined. long InvModStatus(long& x, long a, long n); // if gcd(a,n) = 1, then return-value = 0, x = a^{-1} mod n; // otherwise, return-value = 1, x = gcd(a, n) long PowerMod(long a, long e, long n); // computes a^e mod n (e may be negative) // The following are vector versions of the MulMod routines // They each compute x[i] = (a[i] * b)% n i = 0..k-1 void VectorMulMod(long k, long *x, const long *a, long b, long n); void VectorMulMod(long k, long *x, const long *a, long b, long n, mulmod_t ninv); // ninv = PrepMulMod(n) void VectorMulModPrecon(long k, long *x, const long *a, long b, long n, mulmod_precon_t bninv); // bninv = MulModPrecon(b, n) // The following is provided for legacy support, but is not generally // recommended: long MulDivRem(long& q, long a, long b, long n, muldivrem_t bninv); // return (a*b)%n, set q = (a*b)/n. // The value bninv should be precomputed as // muldivrem_t bninv = PrepMulDivRem(b, n); // or as // muldivrem_t bninv = PrepMulDivRem(b, n, ninv); // where ninv = PrepMod(n). muldivrem_t PrepMulDivRem(long b, long n); muldivrem_t PrepMulDivRem(long b, long n, mulmod_t ninv); // Prepare auxiliary data for MulDivRem. // In the second version, ninv = PrepMulMod(n). // NOTE: despite the similarity in the interface to MulModPrecon, // this routine is typically implemented in a very different way, // and usually much less efficient. // It was initially designed for specialized, internal use // within NTL, but has been a part of the documented NTL // interface for some time, and remains so even after the // v9.0 upgrade. // // Compatibility notes: // // The types mulmod_t and muldivrem_t were introduced in NTL v9.0, as were the // functions PrepMulMod and PrepMulDivRem. Prior to this, the built-in type // "double" played the role of these types, and the user was expected to // compute PrepMulMod(n) as 1/double(n) and PrepMulDivRem(b, n) as // double(b)/double(n). // // By abstracting these types, NTL is able to exploit a wider variety of // implementation strategies. Some old client code may break, but the compiler // will easily find the code that needs to be updated, and the updates are // quite mechanical (unless the old code implicitly made use of the assumption // that NTL_SP_NBITS <= NTL_DOUBLE_PRECISION-3). // // It is highly recommended that old client codes be updated. However, one may // build NTL with the configuration option NTL_LEGACY_SP_MULMOD=on, which will // cause the interfaces and implementations to revert to their pre-v9.0 // definitions. This option will also make the following (obsolete) function // visible: long MulMod2(long a, long b, long n, double bninv); // return (a*b)%n. bninv = ((double) b)/((double) n). This is faster // if both n and b are fixed for many multiplications. // Note: This is OBSOLETE -- use MulModPrecon. // As of v9.2 of NTL, this new interface allows for 60-bit moduli on most // 64-bit machines. The requirement is that a working 128-bit integer type is // available. For current versions of gcc, clang, and icc, this is available // vie the types __int128_t and __uint128_t. If this requirement is met (which // is verified during NTL installation), then a "long long" implementation for // MulMod is used. In versions 9.0 and 9.1 of NTL, a "long double" // implementation was introduced, which utilized the 80-bit extended double // precision hardware on x86 machines. This also allows for 60-bit moduli on // 64-bit machines. // If 128-bit integer types are not available, or if you build NTL with the // NTL_DISABLE_LONGLONG=on flag, NTL will attempt to use the extended double // precision hardware to still allow 60-bit moduli. If that is not possible, // or if you build NTL with the NTL_DISABLE_LONGDOUBLE=on flag, then NTL will // fall back to its "classical" implementation (pre-9.0) that relies on // double-precision arithmetic and imposes a 50-bit limit on moduli. // Note that in on 64-bit machines, either the "long long" or "long double" // implementations could support 62-bit moduli, rather than 60-bit moduli. // However, the restriction to 60-bits speeds up a few things, and so seems // like a good trade off. This is subject to change in the future. // Also note that all of these enhancements introduced since v9.0 are only // available to builds of NTL that use GMP. Builds that don't use GMP will // still be restricted to 50-bit moduli on 64-bit machines. // On machines with 32-bit longs, moduli will be resricted to 30 bits, // regardless on the implementation, which will be based on "long long" // arithmetic (if a 64-bit integer type is available), or on double-precision // floating point (otherwise). // One can detect the new (v9) interface by testing if the macro // NTL_HAVE_MULMOD_T is defined. The following code can be used to make // new-style NTL clients work with either older (pre-9.0) versions of NTL or // newer versions (post-9.0): #ifndef NTL_HAVE_MULMOD_T namespace NTL { typedef double mulmod_t; typedef double muldivrem_t; static inline double PrepMulMod(long n) { return double(1L)/double(n); } static inline double PrepMulDivRem(long b, long n, double ninv) { return double(b)*ninv; } static inline double PrepMulDivRem(long b, long n) { return double(b)/double(n); } static inline double PrepMulModPrecon(long b, long n) { return PrepMulModPrecon(b, n, PrepMulMod(n)); } } #endif /**************************************************************************\ Shift Operations LeftShift by n means multiplication by 2^n RightShift by n means division by 2^n, with truncation toward zero (so the sign is preserved). A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ operator<<(const ZZ& a, long n); ZZ operator>>(const ZZ& a, long n); ZZ& operator<<=(ZZ& x, long n); ZZ& operator>>=(ZZ& x, long n); // procedural versions: void LeftShift(ZZ& x, const ZZ& a, long n); ZZ LeftShift(const ZZ& a, long n); void RightShift(ZZ& x, const ZZ& a, long n); ZZ RightShift(const ZZ& a, long n); /**************************************************************************\ Bits and Bytes \**************************************************************************/ long MakeOdd(ZZ& x); // removes factors of 2 from x, returns the number of 2's removed // returns 0 if x == 0 long NumTwos(const ZZ& x); // returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0. long IsOdd(const ZZ& a); // test if a is odd long NumBits(const ZZ& a); long NumBits(long a); // returns the number of bits in binary represenation of |a|; // NumBits(0) = 0 long bit(const ZZ& a, long k); long bit(long a, long k); // returns bit k of |a|, position 0 being the low-order bit. // If k < 0 or k >= NumBits(a), returns 0. void trunc(ZZ& x, const ZZ& a, long k); // x = low order k bits of |a|. // If k <= 0, x = 0. // two functional variants: ZZ trunc_ZZ(const ZZ& a, long k); long trunc_long(const ZZ& a, long k); long SetBit(ZZ& x, long p); // returns original value of p-th bit of |a|, and replaces p-th bit of // a by 1 if it was zero; low order bit is bit 0; error if p < 0; // the sign of x is maintained long SwitchBit(ZZ& x, long p); // returns original value of p-th bit of |a|, and switches the value // of p-th bit of a; low order bit is bit 0; error if p < 0 // the sign of x is maintained long weight(const ZZ& a); // returns Hamming weight of |a| long weight(long a); // bit-wise Boolean operations, procedural form: void bit_and(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| AND |b| void bit_or(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| OR |b| void bit_xor(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| XOR |b| // bit-wise Boolean operations, operator notation: ZZ operator&(const ZZ& a, const ZZ& b); ZZ operator|(const ZZ& a, const ZZ& b); ZZ operator^(const ZZ& a, const ZZ& b); // PROMOTIONS: the above bit-wise operations (both procedural // and operator forms) provide promotions from long to ZZ on (a, b). ZZ& operator&=(ZZ& x, const ZZ& b); ZZ& operator&=(ZZ& x, long b); ZZ& operator|=(ZZ& x, const ZZ& b); ZZ& operator|=(ZZ& x, long b); ZZ& operator^=(ZZ& x, const ZZ& b); ZZ& operator^=(ZZ& x, long b); // conversions between byte sequences and ZZ's void ZZFromBytes(ZZ& x, const unsigned char *p, long n); ZZ ZZFromBytes(const unsigned char *p, long n); // x = sum(p[i]*256^i, i=0..n-1). // NOTE: in the unusual event that a char is more than 8 bits, // only the low order 8 bits of p[i] are used void BytesFromZZ(unsigned char *p, const ZZ& a, long n); // Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n. long NumBytes(const ZZ& a); long NumBytes(long a); // returns # of base 256 digits needed to represent abs(a). // NumBytes(0) == 0. // @anchor{prg} /**************************************************************************\ Pseudo-Random Numbers \**************************************************************************/ // Routines for generating pseudo-random numbers. // These routines generate high qualtity, cryptographically strong // pseudo-random numbers. They are implemented so that their behaviour // is completely independent of the underlying hardware and long // integer implementation. Note, however, that other routines // throughout NTL use pseudo-random numbers, and because of this, // the word size of the machine can impact the sequence of numbers // seen by a client program. void SetSeed(const ZZ& s); void SetSeed(const unsigned char *data, long dlen); void SetSeed(const RandomStream& s); // Initializes generator with a "seed". // The first version hashes the binary representation of s to obtain a key for // a low-level RandomStream object (see below). // The second version does the same, hashing the first dlen bytes pointed to by // data to obtain a key for the RandomStream object. // The third version initializes the PRG state directly with the given // RandomStream object. // EXCEPTIONS: strong ES void RandomBnd(ZZ& x, const ZZ& n); ZZ RandomBnd(const ZZ& n); void RandomBnd(long& x, long n); long RandomBnd(long n); // x = pseudo-random number in the range 0..n-1, or 0 if n <= 0 // EXCEPTIONS: strong ES void VectorRandomBnd(long k, long *x, long n); // equivalent to x[i] = RandomBnd(n) for i in [0..k), but faster // EXCEPTIONS: strong ES void VectorRandomWord(long k, long *x); // equivalent to x[i] = RandomWord(n) for i in [0..k), but faster // EXCEPTIONS: strong ES void RandomBits(ZZ& x, long l); ZZ RandomBits_ZZ(long l); void RandomBits(long& x, long l); long RandomBits_long(long l); // x = pseudo-random number in the range 0..2^l-1. // EXCEPTIONS: strong ES void RandomLen(ZZ& x, long l); ZZ RandomLen_ZZ(long l); void RandomLen(long& x, long l); long RandomLen_long(long l); // x = psuedo-random number with precisely l bits, // or 0 of l <= 0. // EXCEPTIONS: strong ES unsigned long RandomBits_ulong(long l); // returns a pseudo-random number in the range 0..2^l-1 // EXCEPTIONS: strong ES unsigned long RandomWord(); // returns a word filled with pseudo-random bits. // Equivalent to RandomBits_ulong(NTL_BITS_PER_LONG). // EXCEPTIONS: strong ES class RandomStream { // The low-level pseudo-random generator (PRG). // After initializing it with a key, one can effectively read an unbounded // stream of pseudorandom bytes public: explicit RandomStream(const unsigned char *key); // key should point to an array of NTL_PRG_KEYLEN bytes // EXCEPTIONS: strong ES void get(unsigned char *res, long n); // read the next n bytes from the stream and store to location pointed to by // res // EXCEPTIONS: throws a LogicError exception if n is negative RandomStream(const RandomStream&); // EXCEPTIONS: strong ES RandomStream& operator=(const RandomStream&); // EXCEPTIONS: strong ES }; RandomStream& GetCurrentRandomStream(); // get reference to the current PRG state. If SetSeed has not been called, it // is called with a default value (which should be unique to each // process/thread). NOTE: this is a reference to a thread-local object, so // different threads will use different PRG's, and by default, each will be // initialized with a unique seed. // NOTE: using this reference, you can copy the current PRG state or assign a // different value to it; however, see the helper class RandomStreamPush below, // which may be more convenient. // EXCEPTIONS: strong ES class RandomStreamPush { // RAII for saving/restoring current PRG state public: RandomStreamPush(); // save a copy of the current PRG state // EXCEPTIONS: strong ES ~RandomStreamPush(); // restore the saved copy of the PRG state private: RandomStreamPush(const RandomStreamPush&); // disable void operator=(const RandomStreamPush&); // disable }; void DeriveKey(unsigned char *key, long klen, const unsigned char *data, long dlen); // utility routine to derive from the byte string (data, dlen) a byte string // (key, klen). Heuristically, if (data, dlen) has high entropy, then (key, // klen) should be pseudorandom. This routine is also used internally to // derive PRG keys. // EXCEPTIONS: throws LogicError exception if klen < 0 or hlen < 0 /**************************************************************************\ Incremental Chinese Remaindering \**************************************************************************/ long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P); long CRT(ZZ& a, ZZ& p, long A, long P); // 0 <= A < P, (p, P) = 1; computes a' such that a' = a mod p, // a' = A mod P, and -p*P/2 < a' <= p*P/2; sets a := a', p := p*P, and // returns 1 if a's value has changed, otherwise 0 /**************************************************************************\ Rational Reconstruction \**************************************************************************/ long ReconstructRational(ZZ& a, ZZ& b, const ZZ& x, const ZZ& m, const ZZ& a_bound, const ZZ& b_bound); // 0 <= x < m, m > 2 * a_bound * b_bound, // a_bound >= 0, b_bound > 0 // This routine either returns 0, leaving a and b unchanged, // or returns 1 and sets a and b so that // (1) a = b x (mod m), // (2) |a| <= a_bound, 0 < b <= b_bound, and // (3) gcd(m, b) = gcd(a, b). // If there exist a, b satisfying (1), (2), and // (3') gcd(m, b) = 1, // then a, b are uniquely determined if we impose the additional // condition that gcd(a, b) = 1; moreover, if such a, b exist, // then these values are returned by the routine. // Unless the calling routine can *a priori* guarantee the existence // of a, b satisfying (1), (2), and (3'), // then to ensure correctness, the calling routine should check // that gcd(m, b) = 1, or equivalently, gcd(a, b) = 1. // This is implemented using a variant of Lehmer's extended // Euclidean algorithm. // Literature: see G. Collins and M. Encarnacion, J. Symb. Comp. 20:287-297, // 1995; P. Wang, M. Guy, and J. Davenport, SIGSAM Bulletin 16:2-3, 1982. /**************************************************************************\ Primality Testing and Prime Number Generation \**************************************************************************/ void GenPrime(ZZ& n, long l, long err = 80); ZZ GenPrime_ZZ(long l, long err = 80); long GenPrime_long(long l, long err = 80); // GenPrime generates a random prime n of length l so that the // probability that the resulting n is composite is bounded by 2^(-err). // This calls the routine RandomPrime below, and uses results of // Damgard, Landrock, Pomerance to "optimize" // the number of Miller-Rabin trials at the end. // Note that the prime generated by GenPrime and RandomPrime // is not entirely platform independent. The behavior of the // algorithm can depend on the size parameters, such as NTL_SP_NBITS // NTL_ZZ_NBITS, and NTL_BITS_PER_LONG. However, on a given platform // you will always get the same prime if you run the algorithm // with the same RandomStream. // Note that RandomPrime and GenPrime are thread boosted. // Nevertheless, their behavior is independent of the number of // available threads and any indeterminacy arising from // concurrent computation. void GenGermainPrime(ZZ& n, long l, long err = 80); ZZ GenGermainPrime_ZZ(long l, long err = 80); long GenGermainPrime_long(long l, long err = 80); // A (Sophie) Germain prime is a prime p such that p' = 2*p+1 is also a prime. // Such primes are useful for cryptographic applications...cryptographers // sometimes call p' a "strong" or "safe" prime. // GenGermainPrime generates a random Germain prime n of length l // so that the probability that either n or 2*n+1 is not a prime // is bounded by 2^(-err). // Note that GenGermainPrime is thread boosted. // Nevertheless, its behavior is independent of the number of // available threads and any indeterminacy arising from // concurrent computation. long ProbPrime(const ZZ& n, long NumTrials = 10); long ProbPrime(long n, long NumTrials = 10); // performs trial division, followed by one Miller-Rabin test // to the base 2, followed by NumTrials Miller-witness tests // with random bases. void RandomPrime(ZZ& n, long l, long NumTrials=10); ZZ RandomPrime_ZZ(long l, long NumTrials=10); long RandomPrime_long(long l, long NumTrials=10); // n = random l-bit prime. Uses ProbPrime with NumTrials. void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10); ZZ NextPrime(const ZZ& m, long NumTrials=10); // n = smallest prime >= m. Uses ProbPrime with NumTrials. long NextPrime(long m, long NumTrials=10); // Single precision version of the above. // Result will always be bounded by NTL_ZZ_SP_BOUND, and an // error is raised if this cannot be satisfied. long MillerWitness(const ZZ& n, const ZZ& w); // Tests if w is a witness to compositeness a la Miller. Assumption: n is // odd and positive, 0 <= w < n. // Return value of 1 implies n is composite. // Return value of 0 indicates n might be prime. /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ& x, const ZZ& a, long e); // x = a^e (e >= 0) ZZ power(const ZZ& a, long e); void power(ZZ& x, long a, long e); // two functional variants: ZZ power_ZZ(long a, long e); long power_long(long a, long e); void power2(ZZ& x, long e); // x = 2^e (e >= 0) ZZ power2_ZZ(long e); /**************************************************************************\ Square Roots \**************************************************************************/ void SqrRoot(ZZ& x, const ZZ& a); // x = floor(a^{1/2}) (a >= 0) ZZ SqrRoot(const ZZ& a); long SqrRoot(long a); /**************************************************************************\ Jacobi symbol and modular square roots \**************************************************************************/ long Jacobi(const ZZ& a, const ZZ& n); // compute Jacobi symbol of a and n; assumes 0 <= a < n, n odd void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n); ZZ SqrRootMod(const ZZ& a, const ZZ& n); // computes square root of a mod n; assumes n is an odd prime, and // that a is a square mod n, with 0 <= a < n. /**************************************************************************\ Input/Output I/O Format: Numbers are written in base 10, with an optional minus sign. \**************************************************************************/ istream& operator>>(istream& s, ZZ& x); ostream& operator<<(ostream& s, const ZZ& a); /**************************************************************************\ Miscellany \**************************************************************************/ // The following macros are defined: #define NTL_ZZ_NBITS (...) // number of bits in a limb; // a ZZ is represented as a sequence of limbs. #define NTL_SP_NBITS (...) // max number of bits in a "single-precision" number #define NTL_WSP_NBITS (...) // max number of bits in a "wide single-precision" // number // The following relations hold: // 30 <= NTL_SP_NBITS <= NTL_WSP_NBITS // <= min(NTL_ZZ_NBITS, NTL_BITS_PER_LONG-2) // Note that NTL_ZZ_NBITS may be less than, equal to, or greater than // NTL_BITS_PER_LONG -- no particular relationship should be assumed to hold. // In particular, expressions like (1L << NTL_ZZ_BITS) might overflow. // // "single-precision" numbers are meant to be used in conjunction with the // single-precision modular arithmetic routines. // // "wide single-precision" numbers are meant to be used in conjunction // with the ZZ arithmetic routines for optimal efficiency. // The following auxiliary macros are also defined #define NTL_FRADIX (...) // double-precision value of 2^NTL_ZZ_NBITS #define NTL_SP_BOUND (1L << NTL_SP_NBITS) #define NTL_WSP_BOUND (1L << NTL_WSP_NBITS) // Backward compatibility notes: // // Prior to version 5.0, the macro NTL_NBITS was defined, // along with the macro NTL_RADIX defined to be (1L << NTL_NBITS). // While these macros are still available when using NTL's traditional // long integer package (i.e., when NTL_GMP_LIP is not set), // they are not available when using the GMP as the primary long integer // package (i.e., when NTL_GMP_LIP is set). // Furthermore, when writing portable programs, one should avoid these macros. // Note that when using traditional long integer arithmetic, we have // NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS. // // Prior to version 9.0, one could also assume that // NTL_SP_NBITS <= NTL_DOUBLE_PRECISION-3; // however, this is no longer the case (unless NTL is build with he NTL_LEGACY_SP_MULMOD // flag turned on). // Here are some additional functions. void clear(ZZ& x); // x = 0 void set(ZZ& x); // x = 1 void swap(ZZ& x, ZZ& y); // swap x and y (done by "pointer swapping", if possible). double log(const ZZ& a); // returns double precision approximation to log(a) long NextPowerOfTwo(long m); // returns least nonnegative k such that 2^k >= m long ZZ::size() const; // a.size() returns the number of limbs of |a|; the // size of 0 is 0. void ZZ::SetSize(long k) // a.SetSize(k) does not change the value of a, but simply pre-allocates // space for k limbs. long ZZ::SinglePrecision() const; // a.SinglePrecision() is a predicate that tests if abs(a) < NTL_SP_BOUND long ZZ::WideSinglePrecision() const; // a.WideSinglePrecision() is a predicate that tests if abs(a) < NTL_WSP_BOUND long digit(const ZZ& a, long k); // returns k-th limb of |a|, position 0 being the low-order // limb. // OBSOLETE: this routine is only available when using NTL's traditional // long integer arithmetic, and should not be used in programs // that are meant to be portable. You should instead use the // routine ZZ_limbs_get, defined in ZZ_limbs.h. void ZZ::kill(); // a.kill() sets a to zero and frees the space held by a. void ZZ::swap(ZZ& x); // swap method (done by "pointer swapping" if possible) ZZ::ZZ(INIT_SIZE_TYPE, long k); // ZZ(INIT_SIZE, k) initializes to 0, but space is pre-allocated so // that numbers x with x.size() <= k can be stored without // re-allocation. static const ZZ& ZZ::zero(); // ZZ::zero() yields a read-only reference to zero, if you need it. /**************************************************************************\ Small Prime Generation primes are generated in sequence, starting at 2, and up to a maximum that is no more than min(NTL_SP_BOUND, 2^30). Example: print the primes up to 1000 #include main() { PrimeSeq s; long p; p = s.next(); while (p <= 1000) { cout << p << "\n"; p = s.next(); } } \**************************************************************************/ class PrimeSeq { public: PrimeSeq(); ~PrimeSeq(); long next(); // returns next prime in the sequence. returns 0 if list of small // primes is exhausted. void reset(long b); // resets generator so that the next prime in the sequence is the // smallest prime >= b. private: PrimeSeq(const PrimeSeq&); // disabled void operator=(const PrimeSeq&); // disabled }; ntl-11.5.1/doc/ZZ_limbs.txt0000644417616742025610000000246114064716022017217 0ustar gid-shoupvpug-gid-shoupv/**************************************************************************\ MODULE: ZZ_limbs SUMMARY: Defines low-level access to the "limbs" of a ZZ. \**************************************************************************/ #include #ifdef NTL_GMP_LIP #include #endif // NOTE: unlike other NTL header files, this one needs access // to GMP's header file, which means that C++ files that include // this file will need to ensure that the compiler has the // right "include path" to get at GMP's header file. typedef ... ZZ_limb_t; // The type of a limb. // With GMP, this is mp_limb_t, wich is usually (but not always) // typedef'd to unsigned long. // Without GMP, this is unisigned long (although that is subject to change). // In any case, all that one should assume is that this is an // unisgned integral type. #define NTL_BITS_PER_LIMB_T (...) // Integral constant defining the number of bits of ZZ_limb_t. const ZZ_limb_t * ZZ_limbs_get(const ZZ& a); // Get a pointer to the limbs of a (possibly null). // The number of limbs can be obtained by invoking a.size(). void ZZ_limbs_set(ZZ& x, const ZZ_limb_t *p, long n); // Sets the limbs of x to p[0..n-1]. // An error is raised on n < 0 or p == NULL and n > 0. // It will work correctly even if p points to a limb of x // itself. ntl-11.5.1/doc/ZZVec.txt0000644417616742025610000000336614064716022016474 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZVec SUMMARY: The class ZZVec implements vectors of fixed-length ZZ's. You can allocate a vector of ZZ's of a specified length, where the maximum size of each ZZ is also specified. The size is measured in terms of the number of limbs. These parameters can be specified either with a constructor or with SetSize. It is an error to try to re-size a vector of non-zero length, or store a ZZ that doesn't fit. The space can be released with "kill", and then you are free to call SetSize again. If you want more flexible---but less efficient---vectors, use vec_ZZ. \**************************************************************************/ #include class ZZVec { public: ZZVec(); ZZVec& operator=(const ZZVec&); // first kill()'s destination (unless source and destination are // identical) ZZVec(const ZZVec&); ~ZZVec(); ZZVec(ZZVec&& other) noexcept; ZZVec& operator=(ZZVec&& other) noexcept; // move semantics (C++11 only) ZZVec(long n, long d); // sets length to n and max size of each element to d void SetSize(long n, long d); // sets length to n and max size of each element to d long length() const; // length of vector long BaseSize() const; // max size of each element void kill(); // release space ZZ* elts(); const ZZ* elts() const; // pointer to first element ZZ& operator[](long i); const ZZ& operator[](long i) const; // indexing operator; starts at 0; no range checking swap(ZZVec& x); // swap with x by swapping pointers void move(ZZVec& other); // quick move other to *this }; void swap(ZZVec& x, ZZVec& y); // swaps x and y by swapping pointers ntl-11.5.1/doc/ZZX.txt0000644417616742025610000004214414064716022016163 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZX SUMMARY: The class ZZX implements polynomials in ZZ[X], i.e., univariate polynomials with integer coefficients. Polynomial multiplication is implemented using one of 4 different algorithms: 1) classical 2) Karatsuba 3) Schoenhage & Strassen --- performs an FFT by working modulo a "Fermat number" of appropriate size... good for polynomials with huge coefficients and moderate degree 4) CRT/FFT --- performs an FFT by working modulo several small primes...good for polynomials with moderate coefficients and huge degree. The choice of algorithm is somewhat heuristic, and may not always be perfect. Many thanks to Juergen Gerhard for pointing out the deficiency in the NTL-1.0 ZZX arithmetic, and for contributing the Schoenhage/Strassen code. Extensive use is made of modular algorithms to enhance performance (e.g., the GCD algorithm and amny others). \**************************************************************************/ #include #include "zz_pX.h" #include class ZZX { public: ZZX(); // initial value 0 ZZX(const ZZX& a); // copy explicit ZZX(const ZZ& a); // promotion explicit ZZX(long a); // promotion ~ZZX(); ZZX(ZZX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set ZZX& operator=(ZZX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set ZZX(INIT_MONO_TYPE, long i, const ZZ& c); ZZX(INIT_MONO_TYPE, long i, long c); // initial value c*X^i, invoke as ZZX(INIT_MONO, i, c) ZZX(INIT_MONO_TYPE, long i); // initial value X^i, invoke as ZZX(INIT_MONO, i) ZZX& operator=(const ZZX& a); // assignment ZZX& operator=(const ZZ& a); ZZX& operator=(long a); typedef ZZ coeff_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZX& a); // return deg(a); deg(0) == -1. const ZZ& coeff(const ZZX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ& LeadCoeff(const ZZX& a); // returns leading term of a, or zero if a == 0 const ZZ& ConstTerm(const ZZX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZX& x, long i, const ZZ& a); void SetCoeff(ZZX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZX& x); // x is set to the monomial X long IsX(const ZZX& a); // test if x = X ZZ& ZZX::operator[](long i); const ZZ& ZZX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZX& a, const ZZX& b); long operator!=(const ZZX& a, const ZZX& b); long IsZero(const ZZX& a); // test for 0 long IsOne(const ZZX& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, ZZ} to ZZX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZX operator+(const ZZX& a, const ZZX& b); ZZX operator-(const ZZX& a, const ZZX& b); ZZX operator-(const ZZX& a); // unary - ZZX& operator+=(ZZX& x, const ZZX& a); ZZX& operator-=(ZZX& x, const ZZX& a); ZZX& operator++(ZZX& x); // prefix void operator++(ZZX& x, int); // postfix ZZX& operator--(ZZX& x); // prefix void operator--(ZZX& x, int); // postfix // procedural versions: void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b void negate(ZZX& x, const ZZX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, ZZ} // to ZZX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZX operator*(const ZZX& a, const ZZX& b); ZZX& operator*=(ZZX& x, const ZZX& a); // procedural versions: void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b void sqr(ZZX& x, const ZZX& a); // x = a^2 ZZX sqr(const ZZX& a); // PROMOTIONS: operator * and procedure mul promote {long, ZZ} to ZZX // on (a, b). /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZX operator<<(const ZZX& a, long n); ZZX operator>>(const ZZX& a, long n); ZZX& operator<<=(ZZX& x, long n); ZZX& operator>>=(ZZX& x, long n); // procedural versions: void LeftShift(ZZX& x, const ZZX& a, long n); ZZX LeftShift(const ZZX& a, long n); void RightShift(ZZX& x, const ZZX& a, long n); ZZX RightShift(const ZZX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // Given polynomials a, b in ZZ[X], there exist polynomials // q, r in QQ[X] such that a = b*q + r, deg(r) < deg(b). // These routines return q and/or r if q and/or r lie(s) in ZZ[X], // and otherwise raise an error. // Note that if the leading coefficient of b is 1 or -1, // then q and r always lie in ZZ[X], and no error can occur. // For example, you can write f/2 for a ZZX f. If all coefficients // of f are even, the result is f with a factor of two removed; // otherwise, an error is raised. More generally, f/g will be // evaluate q in ZZ[X] such that f = q*g if such a q exists, // and will otherwise raise an error. // See also below the routines for pseudo-division and division // predicates for routines that are perhaps more useful in // some situations. // operator notation: ZZX operator/(const ZZX& a, const ZZX& b); ZZX operator/(const ZZX& a, const ZZ& b); ZZX operator/(const ZZX& a, long b); ZZX operator%(const ZZX& a, const ZZX& b); ZZX& operator/=(ZZX& x, const ZZX& b); ZZX& operator/=(ZZX& x, const ZZ& b); ZZX& operator/=(ZZX& x, long b); ZZX& operator%=(ZZX& x, const ZZX& b); // procedural versions: void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); // computes q, r such that a = b q + r and deg(r) < deg(b). void div(ZZX& q, const ZZX& a, const ZZX& b); void div(ZZX& q, const ZZX& a, const ZZ& b); void div(ZZX& q, const ZZX& a, long b); // same as DivRem, but only computes q void rem(ZZX& r, const ZZX& a, const ZZX& b); // same as DivRem, but only computes r // divide predicates: long divide(ZZX& q, const ZZX& a, const ZZX& b); long divide(ZZX& q, const ZZX& a, const ZZ& b); long divide(ZZX& q, const ZZX& a, long b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZX& a, const ZZX& b); long divide(const ZZX& a, const ZZ& b); long divide(const ZZX& a, long b); // if b | a, returns 1; otherwise returns 0 // These algorithms employ a modular approach, performing the division // modulo small primes (reconstructing q via the CRT). It is // usually much faster than the general division routines above // (especially when b does not divide a). void content(ZZ& d, const ZZX& f); ZZ content(const ZZX& f); // d = content of f, sign(d) == sign(LeadCoeff(f)); content(0) == 0 void PrimitivePart(ZZX& pp, const ZZX& f); ZZX PrimitivePart(const ZZX& f); // pp = primitive part of f, LeadCoeff(pp) >= 0; PrimitivePart(0) == 0 // pseudo-division: void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b); // performs pseudo-division: computes q and r with deg(r) < deg(b), // and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r. Only the classical // algorithm is used. void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b); ZZX PseudoDiv(const ZZX& a, const ZZX& b); // same as PseudoDivRem, but only computes q void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b); ZZX PseudoRem(const ZZX& a, const ZZX& b); // same as PseudoDivRem, but only computes r /**************************************************************************\ GCD's \**************************************************************************/ void GCD(ZZX& d, const ZZX& a, const ZZX& b); ZZX GCD(const ZZX& a, const ZZX& b); // d = gcd(a, b), LeadCoeff(d) >= 0. Uses a modular algorithm. void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b, long deterministic=0); // r = resultant of a and b; if r != 0, then computes s and t such // that: a*s + b*t = r; otherwise s and t not affected. if // !deterministic, then resultant computation may use a randomized // strategy that errs with probability no more than 2^{-80}. /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. \**************************************************************************/ istream& operator>>(istream& s, ZZX& x); ostream& operator<<(ostream& s, const ZZX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZX& x, const ZZX& a); // x = derivative of a ZZX diff(const ZZX& a); long MaxBits(const ZZX& f); // returns max NumBits of coefficients of f void reverse(ZZX& x, const ZZX& a, long hi); ZZX reverse(const ZZX& a, long hi); void reverse(ZZX& x, const ZZX& a); ZZX reverse(const ZZX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ& x, const ZZX& a, long n); vec_ZZ VectorCopy(const ZZX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Arithmetic mod X^n All routines require n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m ZZX trunc(const ZZX& a, long m); void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n); ZZX MulTrunc(const ZZX& a, const ZZX& b, long n); // x = a * b % X^n void SqrTrunc(ZZX& x, const ZZX& a, long n); ZZX SqrTrunc(const ZZX& a, long n); // x = a^2 % X^n void InvTrunc(ZZX& x, const ZZX& a, long n); ZZX InvTrunc(const ZZX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic The modulus f must be monic with deg(f) > 0, and other arguments must have smaller degree. \**************************************************************************/ void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f); ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f); // x = a * b mod f void SqrMod(ZZX& x, const ZZX& a, const ZZX& f); ZZX SqrMod(const ZZX& a, const ZZX& f); // x = a^2 mod f void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f); ZZX MulByXMod(const ZZX& a, const ZZX& f); // x = a*X mod f /**************************************************************************\ traces, norms, resultants, discriminants, minimal and characteristic polynomials \**************************************************************************/ void TraceMod(ZZ& res, const ZZX& a, const ZZX& f); ZZ TraceMod(const ZZX& a, const ZZX& f); // res = trace of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f) void TraceVec(vec_ZZ& S, const ZZX& f); vec_ZZ TraceVec(const ZZX& f); // S[i] = Trace(X^i mod f), for i = 0..deg(f)-1. // f must be a monic polynomial. // The following routines use a modular approach. void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0); ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0); // res = resultant of a and b. If !deterministic, then it may use a // randomized strategy that errs with probability no more than // 2^{-80}. void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0); ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0); // res = norm of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f). If !deterministic, then it may use a randomized strategy // that errs with probability no more than 2^{-80}. void discriminant(ZZ& d, const ZZX& a, long deterministic=0); ZZ discriminant(const ZZX& a, long deterministic=0); // d = discriminant of a = (-1)^{m(m-1)/2} resultant(a, a')/lc(a), // where m = deg(a). If !deterministic, then it may use a randomized // strategy that errs with probability no more than 2^{-80}. void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0); ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0); // g = char poly of (a mod f). f must be monic. If !deterministic, // then it may use a randomized strategy that errs with probability no // more than 2^{-80}. void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f); ZZX MinPolyMod(const ZZX& a, const ZZX& f); // g = min poly of (a mod f). f must be monic, 0 < deg(f), deg(a) < // deg(f). May use a probabilistic strategy that errs with // probability no more than 2^{-80}. /**************************************************************************\ Incremental Chinese Remaindering \**************************************************************************/ long CRT(ZZX& a, ZZ& prod, const zz_pX& A); long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A); // Incremental Chinese Remaindering: If p is the current zz_p/ZZ_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. /**************************************************************************\ vectors of ZZX's \**************************************************************************/ typedef Vec vec_ZZX; // backward compatibility /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZX& x); // x = 0 void set(ZZX& x); // x = 1 void ZZX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). ZZX::ZZX(INIT_SIZE_TYPE, long n); // ZZX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZX& zero(); // ZZX::zero() is a read-only reference to 0 void ZZX::swap(ZZX& x); void swap(ZZX& x, ZZX& y); // swap (by swapping pointers) ZZX::ZZX(long i, const ZZ& c); ZZX::ZZX(long i, long c); // initial value c*X^i, provided for backward compatibility ntl-11.5.1/doc/ZZXFactoring.txt0000644417616742025610000001464714064716022020027 0ustar gid-shoupvpug-gid-shoupv /*****************************************************************************\ MODULE: ZZXFactoring SUMMARY: Routines are provided for factoring in ZZX. See IMPLEMENTATION DETAILS below for a discussion of the algorithms used, and of the flags available for selecting among these algorithms. \*****************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f); const vector(pair_ZZX_long SquareFreeDecomp(const ZZX& f); // input is primitive, with positive leading coefficient. Performs // square-free decomposition. If f = prod_i g_i^i, then u is set to a // lest of pairs (g_i, i). The list is is increasing order of i, with // trivial terms (i.e., g_i = 1) deleted. void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e, long verbose=0); // Using current value p of zz_p::modulus(), this lifts the // square-free factorization a mod p of f to a factorization A mod p^e // of f. It is required that f and all the polynomials in a are // monic. void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0); vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0); // input f is primitive and square-free, with positive leading // coefficient. bnd, if not zero, indicates that f divides a // polynomial h whose Euclidean norm is bounded by 2^{bnd} in absolute // value. This uses the routine SFCanZass in zz_pXFactoring and then // performs a MultiLift, followed by a brute-force search for the // factors. // A number of heuristics are used to speed up the factor-search step. // See "implementation details" below. void factor(ZZ& c, vec_pair_ZZX_long& factors, const ZZX& f, long verbose=0, long bnd=0); // input f is is an arbitrary polynomial. c is the content of f, and // factors is the facrorization of its primitive part. bnd is as in // SFFactor. The routine calls SquareFreeDecomp and SFFactor. void mul(ZZX& x, const vec_pair_ZZX_long& a); ZZX mul(const vec_pair_ZZX_long& a); // multiplies polynomials, with multiplcities. /*****************************************************************************\ IMPLEMENTATION DETAILS To factor a polynomial, first its content is extracted, and it is made squarefree. This is typically very fast. Second, a simple hack is performed: if the polynomial is of the form g(x^l), then an attempt is made to factor g(k^m), for divisors m of l, which can in some cases greatly simplify the factorization task. You can turn this "power hack" on/off by setting the following variable to 1/0: extern thread_local long ZZXFac_PowerHack; // initial value = 1 Third, the polynomial is factored modulo several small primes, and one small prime p is selected as the "best". You can choose the number of small primes that you want to use by setting the following variable: extern thread_local long ZZXFac_InitNumPrimes; // initial value = 7 Fourth, The factorization mod p is "lifted" to a factorization mod p^k for a sufficiently large k. This is done via quadratic Hensel lifting. Despite "folk wisdom" to the contrary, this is much more efficient than linear Hensel lifting, especially since NTL has very fast polynomial arithmetic. After the "lifting phase" comes the "factor recombination phase". The factorization mod p^k may be "finer" than the true factorization over the integers, hence we have to "combine" subsets of modular factors and test if these are factors over the integers. There are two basic strategies: the "Zassenhaus" method and the "van Hoeij" method. The van Hoeij method: The van Hoeij method is fairly new, but it is so much better than the older, Zassenhaus method, that it is now the default. For a description of the method, go to Mark van Hoeij's home page: http://www.openmath.org/~hoeij/ The van Hoeij method is not really a specific algorithm, but a general algorithmic approach: many parameters and strategies have to be selected to obtain a specific algorithm, and it is a challenge to make all of these choices so that the resulting algorithm works fairly well on all input polynomials. Set the following variable to 1 to enable the van Hoeij method, and to 0 to revert to the Zassenhaus method: extern thread_local long ZZXFac_van_Hoeij; // initial value = 1 Note that the "power hack" is still on by default when using van Hoeij's method, but we have arranged things so that the "power hack" strategy is abandoned if it appears to be too much a waste of time. Unlike with the Zassenhaus method, using the "power hack" method with van Hoeij can sometimes be a huge waste of time if one is not careful. The Zassenhaus method: The Zassenhaus method is essentially a brute-force search, but with a lot of fancy "pruning" techniques, as described in the paper [J. Abbott, V. Shoup, P. Zimmermann, "Factoring in Z[x]: the searching phase", ISSAC 2000]. These heuristics are fairly effective, and allow one to easily deal with up to around 30-40 modular factors, which is *much* more than other Zassenhaus-based factorizers can deal with; however, after this, the exponential behavior of the algorithm really starts to dominate. The behaviour of these heuristics can be fine tuned by setting the following global variables: extern thread_local long ZZXFac_MaxNumPrimes; // initial value = 50 // During the factor recombination phase, if not much progress // is being made, occasionally more "local" information is // collected by factoring f modulo another prime. // This "local" information is used to rule out degrees // of potential factors during recombination. // This value bounds the total number of primes modulo which f // is factored. extern thread_local long ZZXFac_MaxPrune; // initial value = 10 // A kind of "meet in the middle" strategy is used // to prune the search space during recombination. // For many (but not all) polynomials, this can greatly // reduce the running time. // When it does work, there is a time-space tradeoff: // If t = ZZXFac_MaxPrune, the running time will be reduced by a factor near // 2^t, but the table will take (at most) t*2^(t-1) bytes of storage. // Note that ZZXFac_MaxPrune is treated as an upper bound on t---the // factoring algorithm may decide to use a smaller value of t for // a number of reasons. \*****************************************************************************/ ntl-11.5.1/doc/ZZ_p.txt0000644417616742025610000002600714064716022016352 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_p SUMMARY: The class ZZ_p is used to represent integers mod p. The modulus p may be any positive integer, not necessarily prime. Objects of the class ZZ_p are represented as a ZZ in the range 0..p-1. An executing program maintains a "current modulus", which is set to p using ZZ_p::init(p). The current modulus *must* be initialized before any operations on ZZ_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes ZZ_pPush and ZZ_pContext below). \**************************************************************************/ #include #include #include class ZZ_p { public: ZZ_p(); // initialize to 0 ZZ_p(const ZZ_p& a); // copy constructor explicit ZZ_p(long a); // promotion constructor ~ZZ_p(); // destructor ZZ_p& operator=(const ZZ_p& a); // assignment ZZ_p& operator=(long a); // assignment ZZ_p(ZZ_p&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set ZZ_p& operator=(ZZ_p&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set static void init(const ZZ& p); // ZZ_p::init(p) sets the modulus to p (p > 1) static const ZZ& modulus(); // ZZ_p::modulus() yields read-only reference to the current // modulus // typedefs to aid in generic programming typedef ZZ rep_type; typedef ZZ_pContext context_type; typedef ZZ_pBak bak_type; typedef ZZ_pPush push_type; typedef ZZ_pX poly_type; }; /**************************************************************************\ Access to representation \**************************************************************************/ const ZZ& rep(const ZZ_p& a); // read-only access to representation of a /****** Example: ******** ZZ x; ZZ_p a; x = rep(a); *************************/ /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_p& a, const ZZ_p& b); long operator!=(const ZZ_p& a, const ZZ_p& b); // PROMOTIONS: the comparison operators provide promotions // from long to ZZ_p on (a, b) long IsZero(const ZZ_p& a); // test for 0 long IsOne(const ZZ_p& a); // test for 1 /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_p operator+(const ZZ_p& a, const ZZ_p& b); ZZ_p operator-(const ZZ_p& a, const ZZ_p& b); ZZ_p operator-(const ZZ_p& a); // unary - ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator+=(ZZ_p& x, long b); ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator-=(ZZ_p& x, long b); ZZ_p& operator++(ZZ_p& x); // prefix void operator++(ZZ_p& x, int); // postfix ZZ_p& operator--(ZZ_p& x); // prefix void operator--(ZZ_p& x, int); // postfix // procedural versions: void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a + b void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a - b void negate(ZZ_p& x, const ZZ_p& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_p operator*(const ZZ_p& a, const ZZ_p& b); ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator*=(ZZ_p& x, long b); // procedural versions: void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a * b void sqr(ZZ_p& x, const ZZ_p& a); // x = a^2 ZZ_p sqr(const ZZ_p& a); // x = a^2 // PROMOTIONS: operator * and procedure mul provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_p operator/(const ZZ_p& a, const ZZ_p& b); ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b); ZZ_p& operator/=(ZZ_p& x, long b); // procedural versions: void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a/b. // By default, if b is not invertible, an error is raised. // If exceptions are enabled, an InvModErrorObject is thrown // (see documentation in the ZZ module); otherwise, the program // aborts with an error message. // For backward compatibility, one can define an error handler // void H(const ZZ_p& b), and setting ZZ_p::DivHandler = H. Then if b // != 0 and b is not invertible, the function H is invoked with b as // its argument. If the error handler function returns to its caller, // error handling proceeds as described above. void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a ZZ_p inv(const ZZ_p& a); // Error handling is the same as above. // PROMOTIONS: operator / and procedure div provide promotions // from long to ZZ_p on (a, b) /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ_p& x, const ZZ_p& a, const ZZ& e); // x = a^e (e may be negative) ZZ_p power(const ZZ_p& a, const ZZ& e); // functional variants void power(ZZ_p& x, const ZZ_p& a, long e); ZZ_p power(ZZ_p& x, const ZZ_p& a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(ZZ_p& x); ZZ_p random_ZZ_p(); // x = random element in ZZ_p. /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const ZZ_p& a); istream& operator>>(istream& s, ZZ_p& x); // a ZZ is read and reduced mod p /**************************************************************************\ Modulus Switching A class ZZ_pPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it: { ZZ_pPush push(p); ... } The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { ZZ_pPush push; // just backup current modulus ... ZZ_p::init(p1); // install p1 ... ZZ_p::init(p2); // install p2 // reinstall original modulus at close of scope } The ZZ_pPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see ZZ_pContext below. There is also an older ZZ_pBak class that may also be useful. .......................................................................... It is critical that ZZ_p objects created under one ZZ_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any ZZ_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. NOTE: the implementation of Vec is specialized to manage memory more efficiently than in the default implementation of Vec. Specifically, contiguous elements in a Vec are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and --- more significantly --- leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec using the default or copy contructor, and to assign or append one Vec to another "out of context". \**************************************************************************/ // A convenient interface for common cases: class ZZ_pPush { public: ZZ_pPush(); // backup current modulus explicit ZZ_pPush(const ZZ& p); explicit ZZ_pPush(const ZZ_pContext& context); // backup current modulus and install the given one private: ZZ_pPush(const ZZ_pPush&); // disabled void operator=(const ZZ_pPush&); // disabled }; // more general context switching: // A ZZ_pContext object has a modulus q (possibly "null") class ZZ_pContext { public: ZZ_pContext(); // q = "null" explicit ZZ_pContext(const ZZ& p); // q = p void save(); // q = CurrentModulus void restore() const; // CurrentModulus = q ZZ_pContext(const ZZ_pContext&); // copy ZZ_pContext& operator=(const ZZ_pContext&); // assignment ~ZZ_pContext(); // destructor }; // An older interface: // To describe this logic, think of a ZZ_pBak object // of having two components: a modulus q (possibly "null") and // an "auto-restore bit" b. class ZZ_pBak { public: ZZ_pBak(); // q = "null", b = 0 ~ZZ_pBak(); // if (b) CurrentModulus = q void save(); // q = CurrentModulus, b = 1 void restore(); // CurrentModulus = q, b = 0 private: ZZ_pBak(const ZZ_pBak&); // copy disabled void operator=(const ZZ_pBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_p& x); // x = 0 void set(ZZ_p& x); // x = 1 static long ZZ_p::ModulusSize(); // ZZ_p::ModulusSize() returns ZZ_p::modulus().size() static const ZZ_p& ZZ_p::zero(); // ZZ_p::zero() yields a read-only reference to zero void swap(ZZ_p& x, ZZ_p& y); // swap x and y (done by "pointer swapping", if possible). void ZZ_p::swap(ZZ& x); // swap member function ZZ_p::ZZ_p(INIT_NO_ALLOC_TYPE); // special constructor: invoke as ZZ_p x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) ZZ_p::ZZ_p(INIT_ALLOC_TYPE); // special constructor: invoke as ZZ_p x(INIT_ALLOC); // initializes x to 0, but allocates space ZZ_p::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-11.5.1/doc/ZZ_pE.txt0000644417616742025610000002447514064716022016466 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_pE SUMMARY: The class ZZ_pE is used to represent polynomials in Z_p[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. The modulus p defining Z_p need not be prime either. Objects of the class ZZ_pE are represented as a ZZ_pX of degree < deg(P). An executing program maintains a "current modulus", which is set to P using ZZ_pE::init(P). The current modulus for ZZ_pE (as well as for ZZ_p) *must* be initialized before an operations on ZZ_pE's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes ZZ_pEPush and ZZ_pEContext below). \**************************************************************************/ #include class ZZ_pE { public: ZZ_pE(); // initial value 0 ZZ_pE(const ZZ_pE& a); // copy constructor explicit ZZ_pE(const ZZ_p& a); // promotion explicit ZZ_pE(long a); // promotion ZZ_pE& operator=(const ZZ_pE& a); // assignment ZZ_pE& operator=(const ZZ_p& a); // assignment ZZ_pE& operator=(long a); // assignment ~ZZ_pE(); // destructor ZZ_pE(ZZ_pE&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN ZZ_pE& operator=(ZZ_pE&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif static void init(const ZZ_pX& P); // ZZ_pE::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const ZZ_pXModulus& modulus(); // ZZ_pE::modulus() yields read-only reference to the current modulus static long degree(); // ZZ_pE::degree() returns deg(P) // typedefs to aid generic programming typedef ZZ_pX rep_type; typedef ZZ_pEContext context_type; typedef ZZ_pEBak bak_type; typedef ZZ_pEPush push_type; typedef ZZ_pEX poly_type; }; const ZZ_pX& rep(const ZZ_pE& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pE& a, const ZZ_pE& b); long operator!=(const ZZ_pE& a, const ZZ_pE& b); long IsZero(const ZZ_pE& a); // test for 0 long IsOne(const ZZ_pE& a); // test for 1 // PROMOTIONS: ==, != promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE operator-(const ZZ_pE& a); ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator+=(ZZ_pE& x, long a); ZZ_pE& operator++(ZZ_pE& x); // prefix void operator++(ZZ_pE& x, int); // postfix ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator-=(ZZ_pE& x, long a); ZZ_pE& operator--(ZZ_pE& x); // prefix void operator--(ZZ_pE& x, int); // postfix // procedural versions: void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a + b void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a - b void negate(ZZ_pE& x, const ZZ_pE& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator*=(ZZ_pE& x, long a); // procedural versions: void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a * b void sqr(ZZ_pE& x, const ZZ_pE& a); // x = a^2 ZZ_pE sqr(const ZZ_pE& a); // PROMOTIONS: *, mul promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b); ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& a); ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& a); ZZ_pE& operator/=(ZZ_pE& x, long a); // procedural versions: void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a/b. If b is not invertible, an error is raised. void inv(ZZ_pE& x, const ZZ_pE& a); ZZ_pE inv(const ZZ_pE& a); // x = 1/a PROMOTIONS: /, div promote {long, ZZ_p} to ZZ_pE on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e); ZZ_pE power(const ZZ_pE& a, const ZZ& e); void power(ZZ_pE& x, const ZZ_pE& a, long e); ZZ_pE power(const ZZ_pE& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(ZZ_pE& x); ZZ_pE random_ZZ_pE(); // x = random element in ZZ_pE. /**************************************************************************\ Norms and Traces \**************************************************************************/ void trace(ZZ_p& x, const ZZ_pE& a); // x = trace of a ZZ_p trace(const ZZ_pE& a); void norm(ZZ_p& x, const ZZ_pE& a); // x = norm of a ZZ_p norm(const ZZ_pE& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const ZZ_pE& a); istream& operator>>(istream& s, ZZ_pE& x); // a ZZ_pX is read and reduced mod p /**************************************************************************\ Modulus Switching A class ZZ_pEPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { ZZ_pEPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { ZZ_pEPush push; // just backup current modulus ... ZZ_pE::init(P1); // install P1 ... ZZ_pE::init(P2); // install P2 // reinstall original modulus as close of scope } The ZZ_pEPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see ZZ_pEContext below. There is also an older ZZ_pEBak class that may also be useful. .......................................................................... It is critical that ZZ_pE objects created under one ZZ_pE modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_pE modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any ZZ_pE object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases class ZZ_pEPush { public: ZZ_pEPush(); // backup current modulus explicit ZZ_pEPush(const ZZ_pX& P); explicit ZZ_pEPush(const ZZ_pEContext& context); // backup current modulus and install the given one private: ZZ_pEPush(const ZZ_pEPush&); // disabled void operator=(const ZZ_pEPush&); // disabled }; // more general context switching: // A ZZ_pEContext object has a modulus Q (possibly "null"), class ZZ_pEContext { public: ZZ_pEContext(); // Q = "null" explicit ZZ_pEContext(const ZZ_pX& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q ZZ_pEContext(const ZZ_pEContext&); // copy ZZ_pEContext& operator=(const ZZ_pEContext&); // assignment ~ZZ_pEContext(); // destructor }; // An older interface: // To describe this logic, think of a ZZ_pEBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class ZZ_pEBak { public: ZZ_pEBak(); // Q = "null", b = 0 ~ZZ_pEBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: ZZ_pEBak(const ZZ_pEBak&); // copy disabled void operator=(const ZZ_pEBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pE& x); // x = 0 void set(ZZ_pE& x); // x = 1 static const ZZ_pE& ZZ_pE::zero(); // ZZ_pE::zero() yields a read-only reference to zero void ZZ_pE::swap(ZZ_pE& x); void swap(ZZ_pE& x, ZZ_pE& y); // swap (done by "pointer swapping", if possible). static ZZ& ZZ_pE::cardinality(); // yields the cardinality, i.e., p^{ZZ_pE::degree()} ZZ_pE::ZZ_pE(INIT_NO_ALLOC_TYPE); // special constructor: invoke as ZZ_pE x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) ZZ_pE::ZZ_pE(INIT_ALLOC_TYPE); // special constructor: invoke as ZZ_pE x(INIT_ALLOC); // initializes x to 0, but allocates space ZZ_pE::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-11.5.1/doc/ZZ_pEX.txt0000644417616742025610000006752714064716022016623 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_pEX SUMMARY: The class ZZ_pEX represents polynomials over ZZ_pE, and so can be used, for example, for arithmentic in GF(p^n)[X]. However, except where mathematically necessary (e.g., GCD computations), ZZ_pE need not be a field. \**************************************************************************/ #include #include class ZZ_pEX { public: ZZ_pEX(); // initial value 0 ZZ_pEX(const ZZ_pEX& a); // copy explicit ZZ_pEX(const ZZ_pE& a); // promotion explicit ZZ_pEX(const ZZ_p& a); explicit ZZ_pEX(long a); ZZ_pEX& operator=(const ZZ_pEX& a); // assignment ZZ_pEX& operator=(const ZZ_pE& a); ZZ_pEX& operator=(const ZZ_p& a); ZZ_pEX& operator=(long a); ~ZZ_pEX(); // destructor ZZ_pEX(ZZ_pEX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN ZZ_pEX& operator=(ZZ_pEX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c); ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c); ZZ_pEX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as ZZ_pEX(INIT_MONO, i, c) ZZ_pEX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as ZZ_pEX(INIT_MONO, i) // typedefs to aid in generic programming typedef ZZ_pE coeff_type; typedef ZZ_pEXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZ_pEX& a); // return deg(a); deg(0) == -1. const ZZ_pE& coeff(const ZZ_pEX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ_pE& LeadCoeff(const ZZ_pEX& a); // returns leading term of a, or zero if a == 0 const ZZ_pE& ConstTerm(const ZZ_pEX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a); void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pEX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZ_pEX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZ_pEX& x); // x is set to the monomial X long IsX(const ZZ_pEX& a); // test if x = X ZZ_pE& ZZ_pEX::operator[](long i); const ZZ_pE& ZZ_pEX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZ_pEX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZ_pEX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZ_pEX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pEX& a, const ZZ_pEX& b); long operator!=(const ZZ_pEX& a, const ZZ_pEX& b); long IsZero(const ZZ_pEX& a); // test for 0 long IsOne(const ZZ_pEX& a); // test for 1 // PROMOTIONS: ==, != promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator-(const ZZ_pEX& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator+=(ZZ_pEX& x, long a); ZZ_pEX& operator++(ZZ_pEX& x); // prefix void operator++(ZZ_pEX& x, int); // postfix ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator-=(ZZ_pEX& x, long a); ZZ_pEX& operator--(ZZ_pEX& x); // prefix void operator--(ZZ_pEX& x, int); // postfix // procedural versions: void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a + b void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a - b void negate(ZZ_pEX& x, const ZZ_pEX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator*=(ZZ_pEX& x, long a); // procedural versions: void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b void sqr(ZZ_pEX& x, const ZZ_pEX& a); // x = a^2 ZZ_pEX sqr(const ZZ_pEX& a); // PROMOTIONS: *, mul promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b). void power(ZZ_pEX& x, const ZZ_pEX& a, long e); // x = a^e (e >= 0) ZZ_pEX power(const ZZ_pEX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ_pEX operator<<(const ZZ_pEX& a, long n); ZZ_pEX operator>>(const ZZ_pEX& a, long n); ZZ_pEX& operator<<=(ZZ_pEX& x, long n); ZZ_pEX& operator>>=(ZZ_pEX& x, long n); // procedural versions: void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX LeftShift(const ZZ_pEX& a, long n); void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX RightShift(const ZZ_pEX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b); ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b); ZZ_pEX operator/(const ZZ_pEX& a, long b); ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& a); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& a); ZZ_pEX& operator/=(ZZ_pEX& x, long a); ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& a); // procedural versions: void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // q = a/b, r = a%b void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b); void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b); void div(ZZ_pEX& q, const ZZ_pEX& a, long b); // q = a/b void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b); // r = a%b long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pEX& a, const ZZ_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when ZZ_pE is a field. \**************************************************************************/ void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < ZZ_pE::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo ZZ_pE::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, ZZ_pEX& x); ostream& operator<<(ostream& s, const ZZ_pEX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZ_pEX& x, const ZZ_pEX& a); // x = derivative of a ZZ_pEX diff(const ZZ_pEX& a); void MakeMonic(ZZ_pEX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi); ZZ_pEX reverse(const ZZ_pEX& a, long hi); void reverse(ZZ_pEX& x, const ZZ_pEX& a); ZZ_pEX reverse(const ZZ_pEX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n); vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(ZZ_pEX& x, long n); ZZ_pEX random_ZZ_pEX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a); ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a); ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a); // b = f(a) void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a); ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a); // b = f(a); uses ModComp algorithm for ZZ_pX void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a); vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b); ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // x = a % X^n ZZ_pEX trunc(const ZZ_pEX& a, long n); void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n); ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n); // x = a * b % X^n void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n); // x = a^2 % X^n void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); ZZ_pEX InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the ZZ_pEXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f); // x = (a * b) % f void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = a^2 % f void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = (a * X) mod f void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build ZZ_pEXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(ZZ_pEX& x, const vec_ZZ_pEX& v, const ZZ_pEX& f) { ZZ_pEXModulus F(f); ZZ_pEX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A ZZ_pEX may be used wherever a ZZ_pEXModulus is required, and a ZZ_pEXModulus may be used wherever a ZZ_pEX is required. \**************************************************************************/ class ZZ_pEXModulus { public: ZZ_pEXModulus(); // initially in an unusable state ZZ_pEXModulus(const ZZ_pEX& f); // initialize with f, deg(f) > 0 ZZ_pEXModulus(const ZZ_pEXModulus&); // copy ZZ_pEXModulus& operator=(const ZZ_pEXModulus&); // assignment ~ZZ_pEXModulus(); // destructor operator const ZZ_pEX& () const; // implicit read-only access to f const ZZ_pEX& val() const; // explicit read-only access to f }; void build(ZZ_pEXModulus& F, const ZZ_pEX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration ZZ_pEXModulus F(f) is // equivalent to ZZ_pEXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const ZZ_pEXModulus& F); // return n=deg(f) void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F); ZZ_pEX PowerMod(const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F); void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, long e, const ZZ_pEXModulus& F); ZZ_pEX PowerMod(const ZZ_pEX& a, long e, const ZZ_pEXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(ZZ_pEX& x, const ZZ& e, const ZZ_pEXModulus& F); ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F); void PowerXMod(ZZ_pEX& x, long e, const ZZ_pEXModulus& F); ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F); // x = X^e % f (e may be negative) void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); // x = a % f void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F); // q = a/f, r = a%f void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F); // q = a/f // operator notation: ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F); ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F); /**************************************************************************\ vectors of ZZ_pEX's \**************************************************************************/ typedef Vec vec_ZZ_pEX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3, const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3, const ZZ_pEX& h, const ZZ_pEXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a ZZ_pEXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct ZZ_pEXArgument { vec_ZZ_pEX H; }; void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); extern thread_local long ZZ_pEXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // ZZ_pEXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in ZZ_pEXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(ZZ_pE& x, const ZZ_pEVector& a, const ZZ_pEX& b); ZZ_pE project(const ZZ_pEVector& a, const ZZ_pEX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEX& h, const ZZ_pEXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k, const ZZ_pEXArgument& H, const ZZ_pEXModulus& F); // same as above, but uses a pre-computed ZZ_pEXArgument class ZZ_pEXTransMultiplier { /* ... */ }; void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F); void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F); vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a, const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Required: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when ZZ_pE is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m); ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{ZZ_pE::degree()}. void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. The routines require that p is prime, but ZZ_pE need not be a field. \**************************************************************************/ void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& h, const ZZ_pEXModulus& F); ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& h, const ZZ_pEXModulus& F); void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h, const ZZ_pEXModulus& F); // x = g(h) mod f void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over ZZ_p. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*ZZ_pE::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m); void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F); ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F); ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F); void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f); vec_ZZ_pE TraceVec(const ZZ_pEX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f); ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& b); ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b); // x = resultant(a, b) // NormMod and resultant require that ZZ_pE is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pEX& x) // x = 0 void set(ZZ_pEX& x); // x = 1 void ZZ_pEX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). ZZ_pEX::ZZ_pEX(INIT_SIZE_TYPE, long n); // ZZ_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZ_pEX& zero(); // ZZ_pEX::zero() is a read-only reference to 0 void ZZ_pEX::swap(ZZ_pEX& x); void swap(ZZ_pEX& x, ZZ_pEX& y); // swap (via "pointer swapping") ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& c); ZZ_pEX::ZZ_pEX(long i, const ZZ_p& c); ZZ_pEX::ZZ_pEX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-11.5.1/doc/ZZ_pEXFactoring.txt0000644417616742025610000001477414064716022020454 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_pEXFactoring SUMMARY: Routines are provided for factorization of polynomials over ZZ_pE, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f); vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f); vec_ZZ_pE FindRoots(const ZZ_pEX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(ZZ_pE& root, const ZZ_pEX& f); ZZ_pE FindRoot(const ZZ_pEX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{ZZ_pE::cardinality()} mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form tmp-*. // The definition of "large" is controlled by the variable extern thread_local double ZZ_pEXFileThresh // which can be set by the user. If the sizes of the tables // exceeds ZZ_pEXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& h, long d, long verbose=0); vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^{ZZ_pE::cardinality()} mod // f. d = degree of irreducible factors of f. This routine // implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0); vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f, long verbose=0); vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // ZZ_pEXArgBound (see ZZ_pEX.txt). void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v); ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const ZZ_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // ZZ_pE::cardinality()^{-iter}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const ZZ_pEX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const ZZ_pEX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pEX& f, long n); ZZ_pEX BuildIrred_ZZ_pEX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g); ZZ_pEX BuildRandomIrred(const ZZ_pEX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{ZZ_pE::cardinality()} mod f. The common degree of the irreducible // factors of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, // h = X^{ZZ_pE::cardinality()} mod f. // The common degree of the irreducible factors of f is // computed Uses a recursive algorithm similar to DetIrredTest. void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& h); ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F, const ZZ_pEX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of ZZ_pE::cardinality(). This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void PowerCompose(ZZ_pEX& w, const ZZ_pEX& h, long d, const ZZ_pEXModulus& F); ZZ_pEX PowerCompose(const ZZ_pEX& h, long d, const ZZ_pEXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of ZZ_pE::cardinality(). This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] ntl-11.5.1/doc/ZZ_pX.txt0000644417616742025610000007112514064716022016503 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_pX SUMMARY: The class ZZ_pX implements polynomial arithmetic modulo p. Polynomial arithmetic is implemented using the FFT, combined with the Chinese Remainder Theorem. A more detailed description of the techniques used here can be found in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. Small degree polynomials are multiplied either with classical or Karatsuba algorithms. \**************************************************************************/ #include #include class ZZ_pX { public: ZZ_pX(); // initialize to 0 ZZ_pX(const ZZ_pX& a); // copy constructor explicit ZZ_pX(const ZZ_p& a); // promotion explicit ZZ_pX(long a); // promotion ZZ_pX& operator=(const ZZ_pX& a); // assignment ZZ_pX& operator=(const ZZ_p& a); // assignment ZZ_pX& operator=(const long a); // assignment ~ZZ_pX(); // destructor ZZ_pX(ZZ_pX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN ZZ_pX& operator=(ZZ_pX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c); ZZ_pX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as ZZ_pX(INIT_MONO, i, c) ZZ_pX(INIT_MONO_TYPE, long i, long c); // initialize to X^i, invoke as ZZ_pX(INIT_MONO, i) // typedefs to aid in generic programming typedef zz_p coeff_type; typedef zz_pE residue_type; typedef zz_pXModulus modulus_type; typedef zz_pXMultiplier multiplier_type; typedef fftRep fft_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const ZZ_pX& a); // return deg(a); deg(0) == -1. const ZZ_p& coeff(const ZZ_pX& a, long i); // returns the coefficient of X^i, or zero if i not in range const ZZ_p& LeadCoeff(const ZZ_pX& a); // returns leading term of a, or zero if a == 0 const ZZ_p& ConstTerm(const ZZ_pX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a); void SetCoeff(ZZ_pX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(ZZ_pX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(ZZ_pX& x); // x is set to the monomial X long IsX(const ZZ_pX& a); // test if x = X ZZ_p& ZZ_pX::operator[](long i); const ZZ_p& ZZ_pX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void ZZ_pX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void ZZ_pX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void ZZ_pX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const ZZ_pX& a, const ZZ_pX& b); long operator!=(const ZZ_pX& a, const ZZ_pX& b); // PROMOTIONS: operators ==, != promote {long, ZZ_p} to ZZ_pX on (a, b). long IsZero(const ZZ_pX& a); // test for 0 long IsOne(const ZZ_pX& a); // test for 1 /**************************************************************************\ Addition \**************************************************************************/ // operator notation: ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator-(const ZZ_pX& a); // unary - ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator+=(ZZ_pX& x, long a); ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator-=(ZZ_pX& x, long a); ZZ_pX& operator++(ZZ_pX& x); // prefix void operator++(ZZ_pX& x, int); // postfix ZZ_pX& operator--(ZZ_pX& x); // prefix void operator--(ZZ_pX& x, int); // postfix // procedural versions: void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote // {long, ZZ_p} to ZZ_pX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& a); ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& a); ZZ_pX& operator*=(ZZ_pX& x, long a); // procedural versions: void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b void sqr(ZZ_pX& x, const ZZ_pX& a); // x = a^2 ZZ_pX sqr(const ZZ_pX& a); // PROMOTIONS: operator * and procedure mul promote {long, ZZ_p} to ZZ_pX // on (a, b). void power(ZZ_pX& x, const ZZ_pX& a, long e); // x = a^e (e >= 0) ZZ_pX power(const ZZ_pX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: ZZ_pX operator<<(const ZZ_pX& a, long n); ZZ_pX operator>>(const ZZ_pX& a, long n); ZZ_pX& operator<<=(ZZ_pX& x, long n); ZZ_pX& operator>>=(ZZ_pX& x, long n); // procedural versions: void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX LeftShift(const ZZ_pX& a, long n); void RightShift(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX RightShift(const ZZ_pX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b); ZZ_pX operator/(const ZZ_pX& a, long b); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b); ZZ_pX& operator/=(ZZ_pX& x, long b); ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b); ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b); // procedural versions: void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // q = a/b, r = a%b void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b); void div(ZZ_pX& q, const ZZ_pX& a, long b); // q = a/b void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b); // r = a%b long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const ZZ_pX& a, const ZZ_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when p is prime. \**************************************************************************/ void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b); // d = gcd(a,b), a s + b t = d // NOTE: A classical algorithm is used, switching over to a // "half-GCD" algorithm for large degree /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are reduced modulo p, and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, ZZ_pX& x); ostream& operator<<(ostream& s, const ZZ_pX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a ZZ_pX diff(const ZZ_pX& a); void MakeMonic(ZZ_pX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case. void reverse(ZZ_pX& x, const ZZ_pX& a, long hi); ZZ_pX reverse(const ZZ_pX& a, long hi); void reverse(ZZ_pX& x, const ZZ_pX& a); ZZ_pX reverse(const ZZ_pX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n); vec_ZZ_p VectorCopy(const ZZ_pX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(ZZ_pX& x, long n); ZZ_pX random_ZZ_pX(long n); // generate a random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a); ZZ_pX BuildFromRoots(const vec_ZZ_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a); ZZ_p eval(const ZZ_pX& f, const ZZ_p& a); // b = f(a) void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a); vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a); // b.SetLength(a.length()). b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b); ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. p should // be prime. /**************************************************************************\ Arithmetic mod X^n All routines require n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a % X^n ZZ_pX trunc(const ZZ_pX& a, long n); void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n); ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n); // x = a * b % X^n void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX SqrTrunc(const ZZ_pX& a, long n); // x = a^2 % X^n void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long n); ZZ_pX InvTrunc(const ZZ_pX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the ZZ_pXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f); // x = (a * b) % f void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f); // x = a^2 % f void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f); // x = (a * X) mod f // NOTE: thread boosting enabled only if x does not alias a void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build a ZZ_pXModulus F for f. This pre-computes information about f that speeds up subsequent computations. It is required that deg(f) > 0 and that LeadCoeff(f) is invertible. As an example, the following routine computes the product modulo f of a vector of polynomials. #include void product(ZZ_pX& x, const vec_ZZ_pX& v, const ZZ_pX& f) { ZZ_pXModulus F(f); ZZ_pX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a ZZ_pX can be used wherever a ZZ_pXModulus is required, and a ZZ_pXModulus can be used wherever a ZZ_pX is required. \**************************************************************************/ class ZZ_pXModulus { public: ZZ_pXModulus(); // initially in an unusable state ZZ_pXModulus(const ZZ_pXModulus&); // copy ZZ_pXModulus& operator=(const ZZ_pXModulus&); // assignment ~ZZ_pXModulus(); ZZ_pXModulus(const ZZ_pX& f); // initialize with f, deg(f) > 0 operator const ZZ_pX& () const; // read-only access to f, implicit conversion operator const ZZ_pX& val() const; // read-only access to f, explicit notation }; void build(ZZ_pXModulus& F, const ZZ_pX& f); // pre-computes information about f and stores it in F. // Note that the declaration ZZ_pXModulus F(f) is equivalent to // ZZ_pXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const ZZ_pXModulus& F); // return n=deg(f) void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F); void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F); ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F); void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F); ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F); // x = X^e % f (e may be negative) void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e, const ZZ_pXModulus& F); void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e, const ZZ_pXModulus& F); ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e, const ZZ_pXModulus& F); // x = (X + a)^e % f (e may be negative) void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F); // x = a % f void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F); // q = a/f, r = a%f void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F); // q = a/f // operator notation: ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F); ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F); /**************************************************************************\ More Pre-Conditioning If you need to compute a * b % f for a fixed b, but for many a's, it is much more efficient to first build a ZZ_pXMultiplier B for b, and then use the MulMod routine below. Here is an example that multiplies each element of a vector by a fixed polynomial modulo f. #include void mul(vec_ZZ_pX& v, const ZZ_pX& b, const ZZ_pX& f) { ZZ_pXModulus F(f); ZZ_pXMultiplier B(b, F); long i; for (i = 0; i < v.length(); i++) MulMod(v[i], v[i], B, F); } \**************************************************************************/ class ZZ_pXMultiplier { public: ZZ_pXMultiplier(); // initially zero ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F); // initializes with b mod F, where deg(b) < deg(F) ZZ_pXMultiplier(const ZZ_pXMultiplier&); // copy ZZ_pXMultiplier& operator=(const ZZ_pXMultiplier&); // assignment ~ZZ_pXMultiplier(); const ZZ_pX& val() const; // read-only access to b }; void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F); // pre-computes information about b and stores it in B; deg(b) < // deg(F) void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); // x = (a * b) % F; deg(a) < deg(F) /**************************************************************************\ vectors of ZZ_pX's \**************************************************************************/ typedef Vec vec_ZZ_pX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3, const ZZ_pX& h, const ZZ_pXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a ZZ_pXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct ZZ_pXArgument { vec_ZZ_pX H; }; void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H, const ZZ_pXModulus& F); extern thread_local long ZZ_pXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // ZZ_pXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in ZZ_pXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(ZZ_p& x, const ZZ_pVector& a, const ZZ_pX& b); ZZ_p project(const ZZ_pVector& a, const ZZ_pX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pX& h, const ZZ_pXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k, const ZZ_pXArgument& H, const ZZ_pXModulus& F); // same as above, but uses a pre-computed ZZ_pXArgument void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); vec_ZZ_p UpdateMap(const vec_ZZ_p& a, const ZZ_pXMultiplier& B, const ZZ_pXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: must have a.length() <= deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output will always have high order zeroes stripped. /**************************************************************************\ Faster Composition and Projection with Pre-Conditioning A new, experimental version of composition with preconditioning. This interface was introduced in NTL v10.3.0, and it should be considered a preliminary interface and subject to change. The class ZZ_pXNewArgument is similar to ZZ_pXArgument, but with a different internal layout. Copy constructor and assignment work. Note that all NTL modular composition and power projection routines, as well as other routines that use modular composition power projection internally, now use this new class. Note also that these routines do not pay any attention to the ZZ_pXArgBound variable. \**************************************************************************/ class ZZ_pXNewArgument { // ... }; void build(ZZ_pXNewArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m); // same functionality as the corresponding ZZ_pXArgument-based routine void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F); // same functionality as the corresponding ZZ_pXArgument-based routine void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k, const ZZ_pXNewArgument& H, const ZZ_pXModulus& F); // same functionality as the corresponding ZZ_pXArgument-based routine /**************************************************************************\ Minimum Polynomials These routines should be used with prime p. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m); ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/p. void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m); ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m); void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F); ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces, norms, resultants These routines should be used with prime p. \**************************************************************************/ void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F); ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F); void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_ZZ_p& S, const ZZ_pX& f); vec_ZZ_p TraceVec(const ZZ_pX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f); ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& b); ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b); // x = resultant(a, b) void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f); ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f); // g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) < // deg(f); this routine works for arbitrary f; if f is irreducible, // it is faster to use the IrredPolyMod routine, and then exponentiate // if necessary (since in this case the CharPoly is just a power of // the IrredPoly). /**************************************************************************\ Miscellany \**************************************************************************/ void clear(ZZ_pX& x) // x = 0 void set(ZZ_pX& x); // x = 1 void ZZ_pX::kill(); // f.kill() sets f to 0 and frees all memory held by f; Equivalent to // f.rep.kill(). ZZ_pX::ZZ_pX(INIT_SIZE_TYPE, long n); // ZZ_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const ZZ_pX& ZZ_pX::zero(); // ZZ_pX::zero() is a read-only reference to 0 void swap(ZZ_pX& x, ZZ_pX& y); // swap x and y (via "pointer swapping") void ZZ_pX::swap(ZZ_pX& x); // swap member function ZZ_pX::ZZ_pX(long i, const ZZ_p& c); ZZ_pX::ZZ_pX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-11.5.1/doc/ZZ_pXFactoring.txt0000644417616742025610000001524114064716022020335 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: ZZ_pXFactoring SUMMARY: Routines are provided for factorization of polynomials over ZZ_p, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f); vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a lest of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_ZZ_p& x, const ZZ_pX& f); vec_ZZ_p FindRoots(const ZZ_pX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(ZZ_p& root, const ZZ_pX& f); ZZ_p FindRoot(const ZZ_pX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX SFBerlekamp(const ZZ_pX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h, long verbose=0); vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^p mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form tmp-*. // The definition of "large" is controlled by the variable extern thread_local double ZZ_pXFileThresh // which can be set by the user. If the sizes of the tables // exceeds ZZ_pXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& h, long d, long verbose=0); vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^p mod f. d = // degree of irreducible factors of f. This routine implements the // algorithm of [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992]. void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0); vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose=0); vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: In most situations, you should use the CanZass factoring // routine, rather than Berlekamp: it is faster and uses less space. void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v); ZZ_pX mul(const vec_pair_ZZ_pX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const ZZ_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // p^{-iter}. This implements an algorithm from [Shoup, J. Symbolic // Comp. 17:371-391, 1994]. long DetIrredTest(const ZZ_pX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const ZZ_pX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(ZZ_pX& f, long n); ZZ_pX BuildIrred_ZZ_pX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g); ZZ_pX BuildRandomIrred(const ZZ_pX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // f is assumed to be an "equal degree" polynomial; h = X^p mod f. // The common degree of the irreducible factors of f is computed This // routine is useful in counting points on elliptic curves long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F); // Same as above, but uses a slightly faster probabilistic algorithm. // The return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& h); ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F, const ZZ_pX& h); // w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h = // X^q mod f, q a power of p. This routine implements an algorithm // from [von zur Gathen and Shoup, Computational Complexity 2:187-224, // 1992]. void PowerCompose(ZZ_pX& w, const ZZ_pX& h, long d, const ZZ_pXModulus& F); ZZ_pX PowerCompose(const ZZ_pX& h, long d, const ZZ_pXModulus& F); // w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q // a power of p. This routine implements an algorithm from [von zur // Gathen and Shoup, Computational Complexity 2:187-224, 1992] ntl-11.5.1/doc/conversions.txt0000644417616742025610000001464414064716022020044 0ustar gid-shoupvpug-gid-shoupvCONVERSIONS notation: typedef unsigned int uint; typedef unsigned long ulong; destination: source int: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p long: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p uint: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ulong: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p ZZ: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR GF2, zz_p, ZZ_p float: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR double: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR xdouble: int, long, uint, ulong, ZZ, float, double, xdouble, RR quad_float: int, long, uint, ulong, ZZ, float, double, quad_float, RR RR: int, long, uint, ulong, ZZ, float, double, xdouble, quad_float, RR ZZ_p: long, ZZ, ZZ_p ZZ_pX: long, ZZ, ZZ_p; ZZX, ZZ_pX; ZZ_pE; vec_ZZ_p zz_p: long, ZZ, zz_p zz_pX: long, ZZ, zz_p; ZZX, zz_pX; zz_pE; vec_zz_p ZZX: long, ZZ; ZZX, GF2X, zz_pX, ZZ_pX; vec_ZZ GF2: long, ZZ, GF2 GF2X: long, ZZ, GF2; ZZX, GF2X; GF2E; vec_GF2 GF2E: long, ZZ, GF2, GF2E; GF2X GF2EX: long, ZZ, GF2, GF2E; ZZX, GF2X, GF2EX; vec_GF2E ZZ_pE: long, ZZ, ZZ_p, ZZ_pE; ZZ_pX ZZ_pEX: long, ZZ, ZZ_p, ZZ_pE; ZZX, ZZ_pX, ZZ_pEX; vec_ZZ_pE zz_pE: long, ZZ, zz_p, zz_pE; zz_pX zz_pEX: long, ZZ, zz_p, zz_pE; ZZX, zz_pX, zz_pEX; vec_zz_pE vec_ZZ: ZZX vec_ZZ_p: ZZ_pX vec_zz_p: zz_pX vec_GF2: GF2X vec_ZZ_pE: ZZ_pEX vec_zz_pE: zz_pEX vec_GF2E: GF2EX ********** NOTES *********** nomenclature: - integral types: int, long, uint, ulong, ZZ - bounded integral types: int, long, uint, ulong - floating point types: float, double, xdouble, quad_float, RR [1] All conversion operators come in procedural or functional form. To convert a of type S to x of type T, you can write conv(x, a); or x = conv(a); E.g., conv(a), conv(a), conv< Vec >, etc. The notation conv(a) was introduced in NTL v6. Prior to this, the notation to_T(a) was used. For backard compatibility, the various "to_T" functions have been retained; however, their use is dicouraged. Also note that new conversions have been added in v6 for which there is no corresponding "to_T" function: for these, one must use the new "conv" notation. Note that conv is implemented as a template function: template T conv(const S& a) { T x; conv(x, a); return x; } Thus, the call conv(a) always resolves to the procedure call conv(x, a). Modern C++ compilers do a pretty good job implementing the "named return value optimization", so this should not create too any unnecessary temporary objects. [2] In addition to the conversions listed, there is a generic conversion from a C-strings (i.e., const char *) to any type T, which is implemented using templates using the input operator >> for type T. So, for example, you can write ZZ x = conv("99999999999999999999999"); Vec v; conv(v, "[1 2 3]"); If the input fails, the conversion operation will raise an error. [3] In addition to the conversions listed, for generic vector types, a template conversion operator is provided: template void conv(Vec& x, const Vec& a) { long n = a.length(); x.SetLength(n); for (long i = 0; i < n; i++) conv(x[i], a[i]); } This provides component-wise conversion. This, if there is a conversion provided from S to T, then there is automatically a conversion provided from Vec to Vec. Note that because of the simple implementation, this input a is not allowed to alias any components of the output x. However, a and x could be the same. Similarly, for generic matrix types Mat, a template conversion operator provides component-wise conversion. Again, the input may not alias the output. [4] All conversions from an integral type to a bounded integral type compute the result modulo 2^n, where n is the number of bits of the destination type: no overflow occurs. [5] All floating point to signed integral conversions compute the floor function *exactly*, unless the destination type is int or long and overflow occurs, in which case the result is undefined. An exception: converting an RR x to int or long will always yield floor(x) modulo 2^n, where n is the number of bits in the destination type. [6] Conversions from floating point to unsigned int and unsigned long are done via conversions to signed long: if the conversion to long overflows, the result is undefined; otherwise, the result is computed modulo 2^n, where n is the number of bits in the destination type. [7] The ZZ to double conversion routine is very precise: the result is the nearest double, breaking ties using the "round to even" rule. Overflow results in +/- Infinity. All this assumes the underlying floating point adheres to the IEEE standard. [8] All conversions to RR round to the current working precision: even converting an RR to an RR. [9] All conversions from long or ZZ to one of the "mod p" types ZZ_p, ZZ_pX, ZZ_pE, ZZ_pEX, zz_p, zz_pX, zz_pE, zz_pEX, GF2, GF2X, GF2E, GF2EX yield the the residue class modulo p (or 2). [10] All polynomial-to-polynomial conversions apply coefficient-wise conversion. Note that as a rule, if a conversion S to T is provided, then there is a corresponding conversion from the polynomial ring S[X] to the polynomial ring T[X]. [11] All polynomial/vector conversions simply copy from/to the coefficient vector of the polynomial. [12] The GF2X/ZZ_pX/zz_pX to GF2E/ZZ_pE/zz_pE conversions reduce the given polynomial modulo the current modulus; the reverse conversions yield the standard representative (smallest degree polynomial). [13] Conversions from GF2, zz_p or ZZ_p to any integral type yeld the standard representative (least non-negative) of the given residue class. ntl-11.5.1/doc/flags.txt0000644417616742025610000000254314064716022016563 0ustar gid-shoupvpug-gid-shoupv Use the compiler flag -DNTL_TRANSITION to help with the transition to NTL 3.0 from earlier versions. This has the effect of undeclaring certain functions whose semantics in 3.0 is different than in versions < 3.0. Thus, one can use the compiler to find the trouble spots. THE LIBRARY CAN NOT BE COMPILED WITH THIS FLAG! ONLY USE TO FIND TRANSITION PROBLEMS IN CLIENT CODE. Undeclares all shift operators for NTL arithmetic type; in versions < 3.0, << was a conversion operator; now it is a shift operator. Undeclares division functions in ZZX; in versions < 3.0, these were defined in terms of pseudo-division; now they are defined as ordinary division with an error being raised if the result is not integral. Explicit pseudo-division functions are now provided for the old semantics. Undeclares the UpdateMap function in for ZZ_pX and zz_pX; in versions < 3.0, the output always had length n; now high-order zeroes are stripped. Undeclares the conversion from GF2X to GF2EX functions; in versions < 3.0, this was defined as creating a constant polynomial by reduction modulo GF2E::modulus(); now, it is defined as a coefiicient-wise "lift". GF2X and GF2EX happened to be called BB and BB_pX in versions < 3.0. Declares assignment and copy for RR to be private. The semantics of these have changed from "copy and round to current precision" to "exact copy". ntl-11.5.1/doc/lzz_p.txt0000644417616742025610000002643214064716022016630 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_p SUMMARY: The class zz_p is used to represent integers mod p, where 1 <= p < NTL_SP_BOUND. Note that NTL_SP_BOUND is usually 2^30 on 32-bit machines and 2^50 on 64-bit machines. The modulus p may be any positive integer, not necessarily prime. Objects of the class zz_p are represented as a long in the range 0..p-1. An executing program maintains a "current modulus", which is set to p using zz_p::init(p). The current modulus *must* be initialized before any operations on zz_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes zz_pPush and zz_pContext below). \**************************************************************************/ #include #include #include class zz_p { public: zz_p(); // initial value 0 zz_p(const zz_p& a); // copy constructor explicit zz_p(long a); // promotion constructor zz_p& operator=(const zz_p& a); // assignment zz_p& operator=(long a); // assignment static void init(long p); // set the modulus to p, where p > 1. This must be called before any // zz_p constructors are invoked. // The number p must have at most NTL_SP_NBITS bits. static long modulus(); // zz_p::modulus() yields read-only reference to the current // modulus // typedefs to aid in generic programming typedef long rep_type; typedef zz_pContext context_type; typedef zz_pBak bak_type; typedef zz_pPush push_type; typedef zz_pX poly_type; }; long rep(zz_p a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(zz_p a, zz_p b); long operator!=(zz_p a, zz_p b); long IsZero(zz_p a); // test for 0 long IsOne(zz_p a); // test for 1 // PROMOTIONS: operators ==, != promote long to zz_p on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_p operator+(zz_p a, zz_p b); zz_p operator-(zz_p a, zz_p b); zz_p operator-(zz_p a); // unary - zz_p& operator+=(zz_p& x, zz_p a); zz_p& operator+=(zz_p& x, long a); zz_p& operator-=(zz_p& x, zz_p a); zz_p& operator-=(zz_p& x, long a); zz_p& operator++(zz_p& x); // prefix void operator++(zz_p& x, int); // postfix zz_p& operator--(zz_p& x); // prefix void operator--(zz_p& x, int); // postfix // procedural versions: void add(zz_p& x, zz_p a, zz_p b); // x = a + b void sub(zz_p& x, zz_p a, zz_p b); // x = a - b void negate(zz_p& x, zz_p a); // x = -a // PROMOTIONS: binary +, -, and procedures add, sub promote // from long to zz_p on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_p operator*(zz_p a, zz_p b); zz_p& operator*=(zz_p& x, zz_p a); zz_p& operator*=(zz_p& x, long a); // procedural versions: void mul(zz_p& x, zz_p a, zz_p b); // x = a * b void sqr(zz_p& x, zz_p a); // x = a^2 zz_p sqr(zz_p a); // PROMOTIONS: operator * and procedure mul promote from long to zz_p // on (a, b). /**************************************************************************\ Division \**************************************************************************/ operator notation: zz_p operator/(z_p a, zz_p b); zz_p& operator/=(zz_p& x, zz_p a); zz_p& operator/=(zz_p& x, long a); procedural versions: void div(zz_p& x, zz_p a, zz_p b); // x = a/b void inv(zz_p& x, zz_p a); zz_p inv(zz_p a); // x = 1/a // PROMOTIONS: operator / and procedure div promote from long to zz_p // on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(zz_p& x, zz_p a, long e); // x = a^e (e may be negative) zz_p power(zz_p a, long e); /**************************************************************************\ Random Elements \**************************************************************************/ void random(zz_p& x); zz_p random_zz_p(); // x = random element in zz_p. Uses RandomBnd from ZZ. void VectorRandom(long k, zz_p *x); // equivalent to random(x[i]) for i in [0..k), but fatser /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, zz_p a); istream& operator>>(istream& s, zz_p& x); // a ZZ is read and reduced mod p /**************************************************************************\ Modulus Switching A class zz_pPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it: { zz_pPush push(p); ... } The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { zz_pPush push; // just backup current modulus ... zz_p::init(p1); // install p1 ... zz_p::init(p2); // install p2 // reinstall original modulus as close of scope } The zz_pPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see zz_pContext below. There is also an older zz_pBak class that may also be useful. .......................................................................... It is critical that zz_p objects created under one zz_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) zz_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any zz_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases: class zz_pPush { public: zz_pPush(); // just backup current modulus explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot); zz_pPush(INIT_FFT_TYPE, long index); zz_pPush(INIT_USER_FFT_TYPE, long p); explicit zz_pPush(const zz_pContext& context); // backup current modulus and install the given one // see documentation for zz_p::init for more details private: zz_pPush(const zz_pPush&); // disabled void operator=(const zz_pPush&); // disabled }; // more general context switching: // A zz_pContext object has a modulus q (possibly "null") class zz_pContext { public: zz_pContext(); // q = "null" explicit zz_pContext(long p); zz_pContext(INIT_FFT_TYPE, long index); zz_pContext(INIT_USER_FFT_TYPE, long p); // q = the given modulus // see documentation for zz_p::init for more details void save(); // q = CurrentModulus void restore() const; // CurrentModulus = q zz_pContext(const zz_pContext&); // copy zz_pContext& operator=(const zz_pContext&); // assignment ~zz_pContext(); // destructor }; / An older interface: // To describe this logic, think of a zz_pBak object // of having two components: a modulus q (possibly "null") and // an "auto-restore bit" b. class zz_pBak { public: zz_pBak(); // q = "null", b = 0 ~zz_pBak(); // if (b) CurrentModulus = q void save(); // q = CurrentModulus, b = 1 void restore(); // CurrentModulus = q, b = 0 private: zz_pBak(const zz_pBak&); // copy disabled void operator=(const zz_pBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_p& x); // x = 0 void set(zz_p& x); // x = 1 static mulmod_t zz_p::ModulusInverse(); // zz_p::ModulusInverse() returns PrepMulMod(zz_p::modulus()) static zz_p zz_p::zero(); // zz_p::zero() yields a read-only reference to zero void swap(zz_p& x, zz_p& y); // swap x and y static void zz_p::init(long p, long maxroot); // Same as ordinary zz_p::init(p), but somewhat more efficient. If you are // going to perform arithmetic modulo a degree n polynomial, in which // case set maxroot to NextPowerOfTwo(n)+1. This is useful, for // example, if you are going to factor a polynomial of degree n modulo // p, and you know n in advance. // If maxroot is set too low, the program will abort with an // appropriate error message. static void zz_p::FFTInit(long i); // sets modulus to the i-th FFT prime (counting from 0). FFT primes // are NTL_SP_NBITS-bit primes p, where p-1 is divisible by a high power // of two. Thus, polynomial arithmetic mod p can be implemented // particularly efficiently using the FFT. As i increases, the power // of 2 that divides p-1 gets smaller, thus placing a more severe // restriction on the degrees of the polynomials to be multiplied. static void zz_p::UserFFTInit(long p); // set the modulus to a user-provided FFT prime p. To be useful, // p-1 should be divisibly by a high power of 2. // The function is a utility routine that may be used to // calculate this value (see below). // If you are going to perform arithmetic modulo a degree n polynomial, // you will want CalcMaxRoot(p) >= NextPowerOfTwo(n)+1. zz_pContext::zz_pContext(long p, long maxroot); // constructor for a zz_pContext with same semantics // as zz_p::init(p, maxroot) above. zz_pContext::zz_pContext(INIT_FFT_TYPE, long i); // constructor for a zz_pContext with same semantics // as zz_p::FFTInit(i) above; invoke as zz_pContext(INIT_FFT, i). zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p); // constructor for a zz_pContext with same semantics // as zz_p::UserFFTInit(p) above; invoke as zz_pContext(INIT_USER_FFT, p). zz_p::zz_p(INIT_NO_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero zz_p::zz_p(INIT_ALLOC_TYPE); // provided for consistency with other classes, initialize to zero zz_p::allocate(); // provided for consistency with other classes, no action long CalcMaxRoot(long p); // p is assumed to be an odd prime. // Returns the largest k such that 2^k divides p-1 // and such that k does not exceed an implementation defined // constant. This represents the max power of two for which // an FFT mod p is supported. void VectorConv(long k, zz_p *x, const ZZ *a); void VectorConv(long k, zz_p *x, const long *a); // equivalent to conv(x[i], a[i]) for i in [0..k), but fatser ntl-11.5.1/doc/lzz_pE.txt0000644417616742025610000002447614064716022016743 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_pE SUMMARY: The class zz_pE is used to represent polynomials in Z_p[X] modulo a polynomial P. The modulus P may be any polynomial with deg(P) > 0, not necessarily irreducible. The modulus p defining Z_p need not be prime either. Objects of the class zz_pE are represented as a zz_pX of degree < deg(P). An executing program maintains a "current modulus", which is set to P using zz_pE::init(P). The current modulus for zz_pE (as well as for zz_p) *must* be initialized before an operations on zz_pE's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus (see classes zz_pEPush and zz_pEContext below). \**************************************************************************/ #include class zz_pE { public: zz_pE(); // initial value 0 zz_pE(const zz_pE& a); // copy constructor explicit zz_pE(const zz_p& a); // promotion explicit zz_pE(long a); // promotion zz_pE& operator=(const zz_pE& a); // assignment zz_pE& operator=(const zz_p& a); // assignment zz_pE& operator=(long a); // assignment ~zz_pE(); // destructor zz_pE(zz_pE&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN zz_pE& operator=(zz_pE&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif static void init(const zz_pX& P); // zz_pE::init(P) initializes the current modulus to P; // required: deg(P) >= 1. static const zz_pXModulus& modulus(); // zz_pE::modulus() yields read-only reference to the current modulus static long degree(); // zz_pE::degree() returns deg(P) // typedefs to aid generic programming typedef zz_pX rep_type; typedef zz_pEContext context_type; typedef zz_pEBak bak_type; typedef zz_pEPush push_type; typedef zz_pEX poly_type; }; const zz_pX& rep(const zz_pE& a); // read-only access to representation of a /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pE& a, const zz_pE& b); long operator!=(const zz_pE& a, const zz_pE& b); long IsZero(const zz_pE& a); // test for 0 long IsOne(const zz_pE& a); // test for 1 // PROMOTIONS: ==, != promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pE operator+(const zz_pE& a, const zz_pE& b); zz_pE operator-(const zz_pE& a, const zz_pE& b); zz_pE operator-(const zz_pE& a); zz_pE& operator+=(zz_pE& x, const zz_pE& a); zz_pE& operator+=(zz_pE& x, const zz_p& a); zz_pE& operator+=(zz_pE& x, long a); zz_pE& operator++(zz_pE& x); // prefix void operator++(zz_pE& x, int); // postfix zz_pE& operator-=(zz_pE& x, const zz_pE& a); zz_pE& operator-=(zz_pE& x, const zz_p& a); zz_pE& operator-=(zz_pE& x, long a); zz_pE& operator--(zz_pE& x); // prefix void operator--(zz_pE& x, int); // postfix // procedural versions: void add(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a + b void sub(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a - b void negate(zz_pE& x, const zz_pE& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pE operator*(const zz_pE& a, const zz_pE& b); zz_pE& operator*=(zz_pE& x, const zz_pE& a); zz_pE& operator*=(zz_pE& x, const zz_p& a); zz_pE& operator*=(zz_pE& x, long a); // procedural versions: void mul(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a * b void sqr(zz_pE& x, const zz_pE& a); // x = a^2 zz_pE sqr(const zz_pE& a); // PROMOTIONS: *, mul promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pE operator/(const zz_pE& a, const zz_pE& b); zz_pE& operator/=(zz_pE& x, const zz_pE& a); zz_pE& operator/=(zz_pE& x, const zz_p& a); zz_pE& operator/=(zz_pE& x, long a); // procedural versions: void div(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a/b. If b is not invertible, an error is raised. void inv(zz_pE& x, const zz_pE& a); zz_pE inv(const zz_pE& a); // x = 1/a PROMOTIONS: /, div promote {long, zz_p} to zz_pE on (a, b). /**************************************************************************\ Exponentiation \**************************************************************************/ void power(zz_pE& x, const zz_pE& a, const ZZ& e); zz_pE power(const zz_pE& a, const ZZ& e); void power(zz_pE& x, const zz_pE& a, long e); zz_pE power(const zz_pE& a, long e); // x = a^e (e may be negative) /**************************************************************************\ Random Elements \**************************************************************************/ void random(zz_pE& x); zz_pE random_zz_pE(); // x = random element in zz_pE. /**************************************************************************\ Norms and Traces \**************************************************************************/ void trace(zz_p& x, const zz_pE& a); // x = trace of a zz_p trace(const zz_pE& a); void norm(zz_p& x, const zz_pE& a); // x = norm of a zz_p norm(const zz_pE& a); /**************************************************************************\ Input/Output \**************************************************************************/ ostream& operator<<(ostream& s, const zz_pE& a); istream& operator>>(istream& s, zz_pE& x); // a zz_pX is read and reduced mod p /**************************************************************************\ Modulus Switching A class zz_pEPush is provided for "backing up" the current modulus and installing a new one. Here is what you do to save the current modulus, temporarily set it to P, and automatically restore it: { zz_pEPush push(P); ... } The constructor for push will save the current modulus, and install P as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm. You could also do the following: { zz_pEPush push; // just backup current modulus ... zz_pE::init(P1); // install P1 ... zz_pE::init(P2); // install P2 // reinstall original modulus as close of scope } The zz_pEPush interface is good for implementing simple stack-like modulus "context switching". For more general context switching, see zz_pEContext below. There is also an older zz_pEBak class that may also be useful. .......................................................................... It is critical that zz_pE objects created under one zz_pE modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) zz_pE modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition is is generally safe to read any zz_pE object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior. \**************************************************************************/ // A convenient interface for common cases class zz_pEPush { public: zz_pEPush(); // backup current modulus explicit zz_pEPush(const zz_pX& p); explicit zz_pEPush(const zz_pEContext& context); // backup current modulus and install the given one private: zz_pEPush(const zz_pEPush&); // disabled void operator=(const zz_pEPush&); // disabled }; // more general context switching: // A zz_pEContext object has a modulus Q (possibly "null"), class zz_pEContext { public: zz_pEContext(); // Q = "null" explicit zz_pEContext(const zz_pX& P); // Q = P void save(); // Q = CurrentModulus void restore() const; // CurrentModulus = Q zz_pEContext(const zz_pEContext&); // copy zz_pEContext& operator=(const zz_pEContext&); // assignment ~zz_pEContext(); // destructor }; // An older interface: // To describe this logic, think of a zz_pEBak object // of having two components: a modulus Q (possibly "null") and // an "auto-restore bit" b. class zz_pEBak { public: zz_pEBak(); // Q = "null", b = 0 ~zz_pEBak(); // if (b) CurrentModulus = Q void save(); // Q = CurrentModulus, b = 1 void restore(); // CurrentModulus = Q, b = 0 private: zz_pEBak(const zz_pEBak&); // copy disabled void operator=(const zz_pEBak&); // assignment disabled }; /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pE& x); // x = 0 void set(zz_pE& x); // x = 1 static const zz_pE& zz_pE::zero(); // zz_pE::zero() yields a read-only reference to zero void zz_pE::swap(zz_pE& x); void swap(zz_pE& x, zz_pE& y); // swap (done by "pointer swapping", if possible). static ZZ& zz_pE::cardinality(); // yields the cardinality, i.e., p^{zz_pE::degree()} zz_pE::zz_pE(INIT_NO_ALLOC_TYPE); // special constructor: invoke as zz_pE x(INIT_NO_ALLOC); // initializes x to 0, but allocates no space (this is now the default) zz_pE::zz_pE(INIT_ALLOC_TYPE); // special constructor: invoke as zz_pE x(INIT_ALLOC); // initializes x to 0, but allocates space zz_pE::allocate(); // useful in conjunction with the INIT_NO_ALLLOC constructor: // x.allocate() will pre-allocate space for x, using the // current modulus ntl-11.5.1/doc/lzz_pEX.txt0000644417616742025610000006747614064716022017102 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_pEX SUMMARY: The class zz_pEX represents polynomials over zz_pE, and so can be used, for example, for arithmentic in GF(p^n)[X]. However, except where mathematically necessary (e.g., GCD computations), zz_pE need not be a field. \**************************************************************************/ #include #include class zz_pEX { public: zz_pEX(); // initial value 0 zz_pEX(const zz_pEX& a); // copy zz_pEX(const zz_pE& a); // promotion zz_pEX(const zz_p& a); zz_pEX(long a); zz_pEX& operator=(const zz_pEX& a); // assignment zz_pEX& operator=(const zz_pE& a); zz_pEX& operator=(const zz_p& a); zz_pEX& operator=(long a); ~zz_pEX(); // destructor zz_pEX(zz_pEX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN zz_pEX& operator=(zz_pEX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c); zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c); zz_pEX(INIT_MONO_TYPE, long i, long c); // initilaize to c*X^i; invoke as zz_pEX(INIT_MONO, i, c) zz_pEX(INIT_MONO_TYPE, long i); // initilaize to X^i; invoke as zz_pEX(INIT_MONO, i) // typedefs to aid in generic programming typedef zz_pE coeff_type; typedef zz_pEXModulus modulus_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const zz_pEX& a); // return deg(a); deg(0) == -1. const zz_pE& coeff(const zz_pEX& a, long i); // returns the coefficient of X^i, or zero if i not in range const zz_pE& LeadCoeff(const zz_pEX& a); // returns leading term of a, or zero if a == 0 const zz_pE& ConstTerm(const zz_pEX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(zz_pEX& x, long i, const zz_pE& a); void SetCoeff(zz_pEX& x, long i, const zz_p& a); void SetCoeff(zz_pEX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(zz_pEX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(zz_pEX& x); // x is set to the monomial X long IsX(const zz_pEX& a); // test if x = X zz_pE& zz_pEX::operator[](long i); const zz_pE& zz_pEX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void zz_pEX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void zz_pEX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void zz_pEX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pEX& a, const zz_pEX& b); long operator!=(const zz_pEX& a, const zz_pEX& b); long IsZero(const zz_pEX& a); // test for 0 long IsOne(const zz_pEX& a); // test for 1 // PROMOTIONS: ==, != promote {long,zz_p,zz_pE} to zz_pEX on (a, b). /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pEX operator+(const zz_pEX& a, const zz_pEX& b); zz_pEX operator-(const zz_pEX& a, const zz_pEX& b); zz_pEX operator-(const zz_pEX& a); zz_pEX& operator+=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator+=(zz_pEX& x, const zz_pE& a); zz_pEX& operator+=(zz_pEX& x, const zz_p& a); zz_pEX& operator+=(zz_pEX& x, long a); zz_pEX& operator++(zz_pEX& x); // prefix void operator++(zz_pEX& x, int); // postfix zz_pEX& operator-=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator-=(zz_pEX& x, const zz_pE& a); zz_pEX& operator-=(zz_pEX& x, const zz_p& a); zz_pEX& operator-=(zz_pEX& x, long a); zz_pEX& operator--(zz_pEX& x); // prefix void operator--(zz_pEX& x, int); // postfix // procedural versions: void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a + b void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a - b void negate(zz_pEX& x, const zz_pEX& a); // x = - a // PROMOTIONS: +, -, add, sub promote {long,zz_p,zz_pE} to zz_pEX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pEX operator*(const zz_pEX& a, const zz_pEX& b); zz_pEX& operator*=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator*=(zz_pEX& x, const zz_pE& a); zz_pEX& operator*=(zz_pEX& x, const zz_p& a); zz_pEX& operator*=(zz_pEX& x, long a); // procedural versions: void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b void sqr(zz_pEX& x, const zz_pEX& a); // x = a^2 zz_pEX sqr(const zz_pEX& a); // PROMOTIONS: *, mul promote {long,zz_p,zz_pE} to zz_pEX on (a, b). void power(zz_pEX& x, const zz_pEX& a, long e); // x = a^e (e >= 0) zz_pEX power(const zz_pEX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: zz_pEX operator<<(const zz_pEX& a, long n); zz_pEX operator>>(const zz_pEX& a, long n); zz_pEX& operator<<=(zz_pEX& x, long n); zz_pEX& operator>>=(zz_pEX& x, long n); // procedural versions: void LeftShift(zz_pEX& x, const zz_pEX& a, long n); zz_pEX LeftShift(const zz_pEX& a, long n); void RightShift(zz_pEX& x, const zz_pEX& a, long n); zz_pEX RightShift(const zz_pEX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pEX operator/(const zz_pEX& a, const zz_pEX& b); zz_pEX operator/(const zz_pEX& a, const zz_pE& b); zz_pEX operator/(const zz_pEX& a, const zz_p& b); zz_pEX operator/(const zz_pEX& a, long b); zz_pEX operator%(const zz_pEX& a, const zz_pEX& b); zz_pEX& operator/=(zz_pEX& x, const zz_pEX& a); zz_pEX& operator/=(zz_pEX& x, const zz_pE& a); zz_pEX& operator/=(zz_pEX& x, const zz_p& a); zz_pEX& operator/=(zz_pEX& x, long a); zz_pEX& operator%=(zz_pEX& x, const zz_pEX& a); // procedural versions: void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // q = a/b, r = a%b void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b); void div(zz_pEX& q, const zz_pEX& a, const zz_p& b); void div(zz_pEX& q, const zz_pEX& a, long b); // q = a/b void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b); // r = a%b long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pEX& a, const zz_pEX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 /**************************************************************************\ GCD's These routines are intended for use when zz_pE is a field. \**************************************************************************/ void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); zz_pEX GCD(const zz_pEX& a, const zz_pEX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b); // d = gcd(a,b), a s + b t = d /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be polynomials of degree < zz_pE::degree() and a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary polynomials which are reduced modulo zz_pE::modulus(), and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, zz_pEX& x); ostream& operator<<(ostream& s, const zz_pEX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(zz_pEX& x, const zz_pEX& a); // x = derivative of a zz_pEX diff(const zz_pEX& a); void MakeMonic(zz_pEX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case void reverse(zz_pEX& x, const zz_pEX& a, long hi); zz_pEX reverse(const zz_pEX& a, long hi); void reverse(zz_pEX& x, const zz_pEX& a); zz_pEX reverse(const zz_pEX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n); vec_zz_pE VectorCopy(const zz_pEX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(zz_pEX& x, long n); zz_pEX random_zz_pEX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a); zz_pEX BuildFromRoots(const vec_zz_pE& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length() void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a); zz_pE eval(const zz_pEX& f, const zz_pE& a); // b = f(a) void eval(zz_pE& b, const zz_pX& f, const zz_pE& a); zz_pE eval(const zz_pEX& f, const zz_pE& a); // b = f(a); uses ModComp algorithm for zz_pX void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a); vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b); zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. /**************************************************************************\ Arithmetic mod X^n Required: n >= 0; otherwise, an error is raised. \**************************************************************************/ void trunc(zz_pEX& x, const zz_pEX& a, long n); // x = a % X^n zz_pEX trunc(const zz_pEX& a, long n); void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n); zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n); // x = a * b % X^n void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n); zz_pEX SqrTrunc(const zz_pEX& a, long n); // x = a^2 % X^n void InvTrunc(zz_pEX& x, const zz_pEX& a, long n); zz_pEX InvTrunc(zz_pEX& x, const zz_pEX& a, long n); // computes x = a^{-1} % X^m. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the zz_pEXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f); // x = (a * b) % f void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f); // x = a^2 % f void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f); // x = (a * X) mod f void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build zz_pEXModulus F for f. This pre-computes information about f that speeds up subsequent computations. As an example, the following routine the product modulo f of a vector of polynomials. #include void product(zz_pEX& x, const vec_zz_pEX& v, const zz_pEX& f) { zz_pEXModulus F(f); zz_pEX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } NOTE: A zz_pEX may be used wherever a zz_pEXModulus is required, and a zz_pEXModulus may be used wherever a zz_pEX is required. \**************************************************************************/ class zz_pEXModulus { public: zz_pEXModulus(); // initially in an unusable state zz_pEXModulus(const zz_pEX& f); // initialize with f, deg(f) > 0 zz_pEXModulus(const zz_pEXModulus&); // copy zz_pEXModulus& operator=(const zz_pEXModulus&); // assignment ~zz_pEXModulus(); // destructor operator const zz_pEX& () const; // implicit read-only access to f const zz_pEX& val() const; // explicit read-only access to f }; void build(zz_pEXModulus& F, const zz_pEX& f); // pre-computes information about f and stores it in F. Must have // deg(f) > 0. Note that the declaration zz_pEXModulus F(f) is // equivalent to zz_pEXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const zz_pEXModulus& F); // return n=deg(f) void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F); zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(zz_pEX& x, const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F); zz_pEX PowerMod(const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F); void PowerMod(zz_pEX& x, const zz_pEX& a, long e, const zz_pEXModulus& F); zz_pEX PowerMod(const zz_pEX& a, long e, const zz_pEXModulus& F); // x = a^e % f; e >= 0, deg(a) < n. Uses a sliding window algorithm. // (e may be negative) void PowerXMod(zz_pEX& x, const ZZ& e, const zz_pEXModulus& F); zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F); void PowerXMod(zz_pEX& x, long e, const zz_pEXModulus& F); zz_pEX PowerXMod(long e, const zz_pEXModulus& F); // x = X^e % f (e may be negative) void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F); // x = a % f void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F); // q = a/f, r = a%f void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F); // q = a/f // operator notation: zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F); zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F); zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F); zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F); /**************************************************************************\ vectors of zz_pEX's \**************************************************************************/ typedef Vec vec_zz_pEX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h, const zz_pEXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1,2); deg(h) < n. void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3, const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3, const zz_pEX& h, const zz_pEXModulus& F); // xi = gi(h) mod f (i=1..3); deg(h) < n. /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a zz_pEXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct zz_pEXArgument { vec_zz_pEX H; }; void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n. void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H, const zz_pEXModulus& F); extern thread_local long zz_pEXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // zz_pEXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in zz_pEXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(zz_pE& x, const zz_pEVector& a, const zz_pEX& b); zz_pE project(const zz_pEVector& a, const zz_pEX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEX& h, const zz_pEXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k, const zz_pEXArgument& H, const zz_pEXModulus& F); // same as above, but uses a pre-computed zz_pEXArgument class zz_pEXTransMultiplier { /* ... */ }; void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F); void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a, const zz_pEXMultiplier& B, const zz_pEXModulus& F); vec_zz_pE UpdateMap(const vec_zz_pE& a, const zz_pEXMultiplier& B, const zz_pEXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Required: a.length() <= deg(F), deg(b) < deg(F). // This is "transposed" MulMod by B. // Input may have "high order" zeroes stripped. // Output always has high order zeroes stripped. /**************************************************************************\ Minimum Polynomials These routines should be used only when zz_pE is a field. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m); zz_pEX MinPolySeq(const vec_zz_pE& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/2^{zz_pE::degree()}. void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // same as above, but guarantees that result is correct void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m); void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Composition and Minimal Polynomials in towers These are implementations of algorithms that will be described and analyzed in a forthcoming paper. The routines require that p is prime, but zz_pE need not be a field. \**************************************************************************/ void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& h, const zz_pEXModulus& F); zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& h, const zz_pEXModulus& F); void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); zz_pEX CompTower(const zz_pX& g, const zz_pEX& h, const zz_pEXModulus& F); // x = g(h) mod f void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Uses a probabilistic algorithm to compute the minimal // polynomial of (g mod f) over zz_p. // The parameter m is a bound on the degree of the minimal polynomial // (default = deg(f)*zz_pE::degree()). // In general, the result will be a divisor of the true minimimal // polynomial. For correct results, use the MinPoly routines below. void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Same as above, but result is always correct. void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m); zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m); void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F); zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F); // Same as above, but assumes the minimal polynomial is // irreducible, and uses a slightly faster, deterministic algorithm. /**************************************************************************\ Traces, norms, resultants \**************************************************************************/ void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F); zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F); void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_zz_pE& S, const zz_pEX& f); vec_zz_pE TraceVec(const zz_pEX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above trace routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f); zz_pE NormMod(const zz_pEX& a, const zz_pEX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(zz_pE& x, const zz_pEX& a, const zz_pEX& b); zz_pE resultant(const zz_pEX& a, const zz_pEX& b); // x = resultant(a, b) // NormMod and resultant require that zz_pE is a field. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pEX& x) // x = 0 void set(zz_pEX& x); // x = 1 void zz_pEX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). zz_pEX::zz_pEX(INIT_SIZE_TYPE, long n); // zz_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const zz_pEX& zero(); // zz_pEX::zero() is a read-only reference to 0 void zz_pEX::swap(zz_pEX& x); void swap(zz_pEX& x, zz_pEX& y); // swap (via "pointer swapping") zz_pEX::zz_pEX(long i, const zz_pE& c); zz_pEX::zz_pEX(long i, const zz_p& c); zz_pEX::zz_pEX(long i, long c); // initilaize to c*X^i; provided for backward compatibility ntl-11.5.1/doc/lzz_pEXFactoring.txt0000644417616742025610000001477314064716022020727 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_pEXFactoring SUMMARY: Routines are provided for factorization of polynomials over zz_pE, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include #include void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f); vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a list of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_zz_pE& x, const zz_pEX& f); vec_zz_pE FindRoots(const zz_pEX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(zz_pE& root, const zz_pEX& f); zz_pE FindRoot(const zz_pEX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f, const zz_pEX& h, long verbose=0); vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^{zz_pE::cardinality()} mod f. // This routine implements the baby step/giant step algorithm // of [Kaltofen and Shoup, STOC 1995]. // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. // NOTE: When factoring "large" polynomials, // this routine uses external files to store some intermediate // results, which are removed if the routine terminates normally. // These files are stored in the current directory under names of the // form tmp-*. // The definition of "large" is controlled by the variable extern thread_local double zz_pEXFileThresh // which can be set by the user. If the sizes of the tables // exceeds zz_pEXFileThresh KB, external files are used. // Initial value is NTL_FILE_THRESH (defined in tools.h). void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& h, long d, long verbose=0); vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^{zz_pE::cardinality()} mod // f. d = degree of irreducible factors of f. This routine // implements the algorithm of [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0); vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f, long verbose=0); vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: these routines use modular composition. The space // used for the required tables can be controlled by the variable // zz_pEXArgBound (see zz_pEX.txt). void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v); zz_pEX mul(const vec_pair_zz_pEX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const zz_pEX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // zz_pE::cardinality()^{-iter}. This implements an algorithm from [Shoup, // J. Symbolic Comp. 17:371-391, 1994]. long DetIrredTest(const zz_pEX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const zz_pEX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pEX& f, long n); zz_pEX BuildIrred_zz_pEX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pEX& f, const zz_pEX& g); zz_pEX BuildRandomIrred(const zz_pEX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, and h = // X^{zz_pE::cardinality()} mod f. The common degree of the irreducible // factors of f is computed. Uses a "baby step/giant step" algorithm, similar // to NewDDF. Although asymptotocally slower than RecComputeDegree // (below), it is faster for reasonably sized inputs. long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F); // f is assumed to be an "equal degree" polynomial, // h = X^{zz_pE::cardinality()} mod f. // The common degree of the irreducible factors of f is // computed Uses a recursive algorithm similar to DetIrredTest. void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& h); zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F, const zz_pEX& h); // Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, // and h = X^q mod f, q a power of zz_pE::cardinality(). This routine // implements an algorithm from [von zur Gathen and Shoup, // Computational Complexity 2:187-224, 1992] void PowerCompose(zz_pEX& w, const zz_pEX& h, long d, const zz_pEXModulus& F); zz_pEX PowerCompose(const zz_pEX& h, long d, const zz_pEXModulus& F); // Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q // mod f, q a power of zz_pE::cardinality(). This routine implements an // algorithm from [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] ntl-11.5.1/doc/lzz_pX.txt0000644417616742025610000007002314064716023016754 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_pX SUMMARY: The class zz_pX implements polynomial arithmetic modulo p. Polynomial arithmetic is implemented using a combination of classical routines, Karatsuba, and FFT. \**************************************************************************/ #include "zz_p.h" #include "vec_zz_p.h" class zz_pX { public: zz_pX(); // initial value 0 zz_pX(const zz_pX& a); // copy explicit zz_pX(zz_p a); // promotion explicit zz_pX(long a); // promotion zz_pX& operator=(const zz_pX& a); // assignment zz_pX& operator=(zz_p a); zz_pX& operator=(long a); ~zz_pX(); // destructor zz_pX(zz_pX&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #ifndef NTL_DISABLE_MOVE_ASSIGN zz_pX& operator=(zz_pX&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set #endif zz_pX(INIT_MONO_TYPE, long i, zz_p c); zz_pX(INIT_MONO_TYPE, long i, long c); // initialize to c*X^i, invoke as zz_pX(INIT_MONO, i, c) zz_pX(INIT_MONO_TYPE, long i); // initialize to X^i, invoke as zz_pX(INIT_MONO, i) typedef zz_p coeff_type; // ... }; /**************************************************************************\ Accessing coefficients The degree of a polynomial f is obtained as deg(f), where the zero polynomial, by definition, has degree -1. A polynomial f is represented as a coefficient vector. Coefficients may be accesses in one of two ways. The safe, high-level method is to call the function coeff(f, i) to get the coefficient of X^i in the polynomial f, and to call the function SetCoeff(f, i, a) to set the coefficient of X^i in f to the scalar a. One can also access the coefficients more directly via a lower level interface. The coefficient of X^i in f may be accessed using subscript notation f[i]. In addition, one may write f.SetLength(n) to set the length of the underlying coefficient vector to n, and f.SetMaxLength(n) to allocate space for n coefficients, without changing the coefficient vector itself. After setting coefficients using this low-level interface, one must ensure that leading zeros in the coefficient vector are stripped afterwards by calling the function f.normalize(). NOTE: the coefficient vector of f may also be accessed directly as f.rep; however, this is not recommended. Also, for a properly normalized polynomial f, we have f.rep.length() == deg(f)+1, and deg(f) >= 0 => f.rep[deg(f)] != 0. \**************************************************************************/ long deg(const zz_pX& a); // return deg(a); deg(0) == -1. const zz_p coeff(const zz_pX& a, long i); // returns the coefficient of X^i, or zero if i not in range const zz_p LeadCoeff(const zz_pX& a); // returns leading term of a, or zero if a == 0 const zz_p ConstTerm(const zz_pX& a); // returns constant term of a, or zero if a == 0 void SetCoeff(zz_pX& x, long i, zz_p a); void SetCoeff(zz_pX& x, long i, long a); // makes coefficient of X^i equal to a; error is raised if i < 0 void SetCoeff(zz_pX& x, long i); // makes coefficient of X^i equal to 1; error is raised if i < 0 void SetX(zz_pX& x); // x is set to the monomial X long IsX(const zz_pX& a); // test if x = X zz_p& zz_pX::operator[](long i); const zz_p& zz_pX::operator[](long i) const; // indexing operators: f[i] is the coefficient of X^i --- // i should satsify i >= 0 and i <= deg(f). // No range checking (unless NTL_RANGE_CHECK is defined). void zz_pX::SetLength(long n); // f.SetLength(n) sets the length of the inderlying coefficient // vector to n --- after this call, indexing f[i] for i = 0..n-1 // is valid. void zz_pX::normalize(); // f.normalize() strips leading zeros from coefficient vector of f void zz_pX::SetMaxLength(long n); // f.SetMaxLength(n) pre-allocate spaces for n coefficients. The // polynomial that f represents is unchanged. /**************************************************************************\ Comparison \**************************************************************************/ long operator==(const zz_pX& a, const zz_pX& b); long operator!=(const zz_pX& a, const zz_pX& b); long IsZero(const zz_pX& a); // test for 0 long IsOne(const zz_pX& a); // test for 1 // PROMOTIONS: operators ==, != promote {long, zz_p} to zz_pX on (a, b) /**************************************************************************\ Addition \**************************************************************************/ // operator notation: zz_pX operator+(const zz_pX& a, const zz_pX& b); zz_pX operator-(const zz_pX& a, const zz_pX& b); zz_pX operator-(const zz_pX& a); // unary - zz_pX& operator+=(zz_pX& x, const zz_pX& a); zz_pX& operator+=(zz_pX& x, zz_p a); zz_pX& operator+=(zz_pX& x, long a); zz_pX& operator-=(zz_pX& x, const zz_pX& a); zz_pX& operator-=(zz_pX& x, zz_p a); zz_pX& operator-=(zz_pX& x, long a); zz_pX& operator++(zz_pX& x); // prefix void operator++(zz_pX& x, int); // postfix zz_pX& operator--(zz_pX& x); // prefix void operator--(zz_pX& x, int); // postfix // procedural versions: void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b void negate(zz_pX& x, const zz_pX& a); // x = -a // PROMOTIONS: binary +, - and procedures add, sub promote {long, zz_p} // to zz_pX on (a, b). /**************************************************************************\ Multiplication \**************************************************************************/ // operator notation: zz_pX operator*(const zz_pX& a, const zz_pX& b); zz_pX& operator*=(zz_pX& x, const zz_pX& a); zz_pX& operator*=(zz_pX& x, zz_p a); zz_pX& operator*=(zz_pX& x, long a); // procedural versions: void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b void sqr(zz_pX& x, const zz_pX& a); // x = a^2 zz_pX sqr(const zz_pX& a); // PROMOTIONS: operator * and procedure mul promote {long, zz_p} to zz_pX // on (a, b). void power(zz_pX& x, const zz_pX& a, long e); // x = a^e (e >= 0) zz_pX power(const zz_pX& a, long e); /**************************************************************************\ Shift Operations LeftShift by n means multiplication by X^n RightShift by n means division by X^n A negative shift amount reverses the direction of the shift. \**************************************************************************/ // operator notation: zz_pX operator<<(const zz_pX& a, long n); zz_pX operator>>(const zz_pX& a, long n); zz_pX& operator<<=(zz_pX& x, long n); zz_pX& operator>>=(zz_pX& x, long n); // procedural versions: void LeftShift(zz_pX& x, const zz_pX& a, long n); zz_pX LeftShift(const zz_pX& a, long n); void RightShift(zz_pX& x, const zz_pX& a, long n); zz_pX RightShift(const zz_pX& a, long n); /**************************************************************************\ Division \**************************************************************************/ // operator notation: zz_pX operator/(const zz_pX& a, const zz_pX& b); zz_pX operator%(const zz_pX& a, const zz_pX& b); zz_pX& operator/=(zz_pX& x, const zz_pX& a); zz_pX& operator/=(zz_pX& x, zz_p a); zz_pX& operator/=(zz_pX& x, long a); zz_pX& operator%=(zz_pX& x, const zz_pX& b); // procedural versions: void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b); // q = a/b, r = a%b void div(zz_pX& q, const zz_pX& a, const zz_pX& b); // q = a/b void rem(zz_pX& r, const zz_pX& a, const zz_pX& b); // r = a%b long divide(zz_pX& q, const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 long divide(const zz_pX& a, const zz_pX& b); // if b | a, sets q = a/b and returns 1; otherwise returns 0 // PROMOTIONS: operator / and procedure div promote {long, zz_p} to zz_pX // on (a, b). /**************************************************************************\ GCD's These routines are intended for use when p is prime. \**************************************************************************/ void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b); zz_pX GCD(const zz_pX& a, const zz_pX& b); // x = GCD(a, b), x is always monic (or zero if a==b==0). void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b); // d = gcd(a,b), a s + b t = d // NOTE: A classical algorithm is used, switching over to a // "half-GCD" algorithm for large degree /**************************************************************************\ Input/Output I/O format: [a_0 a_1 ... a_n], represents the polynomial a_0 + a_1*X + ... + a_n*X^n. On output, all coefficients will be integers between 0 and p-1, amd a_n not zero (the zero polynomial is [ ]). On input, the coefficients are arbitrary integers which are reduced modulo p, and leading zeros stripped. \**************************************************************************/ istream& operator>>(istream& s, zz_pX& x); ostream& operator<<(ostream& s, const zz_pX& a); /**************************************************************************\ Some utility routines \**************************************************************************/ void diff(zz_pX& x, const zz_pX& a); zz_pX diff(const zz_pX& a); // x = derivative of a void MakeMonic(zz_pX& x); // if x != 0 makes x into its monic associate; LeadCoeff(x) must be // invertible in this case. void reverse(zz_pX& x, const zz_pX& a, long hi); zz_pX reverse(const zz_pX& a, long hi); void reverse(zz_pX& x, const zz_pX& a); zz_pX reverse(const zz_pX& a); // x = reverse of a[0]..a[hi] (hi >= -1); // hi defaults to deg(a) in second version void VectorCopy(vec_zz_p& x, const zz_pX& a, long n); vec_zz_p VectorCopy(const zz_pX& a, long n); // x = copy of coefficient vector of a of length exactly n. // input is truncated or padded with zeroes as appropriate. /**************************************************************************\ Random Polynomials \**************************************************************************/ void random(zz_pX& x, long n); zz_pX random_zz_pX(long n); // x = random polynomial of degree < n /**************************************************************************\ Polynomial Evaluation and related problems \**************************************************************************/ void BuildFromRoots(zz_pX& x, const vec_zz_p& a); zz_pX BuildFromRoots(const vec_zz_p& a); // computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = // a.length() void eval(zz_p& b, const zz_pX& f, zz_p a); zz_p eval(const zz_pX& f, zz_p a); // b = f(a) void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a); vec_zz_p eval(const zz_pX& f, const vec_zz_p& a); // b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length() void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b); zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b); // interpolates the polynomial f satisfying f(a[i]) = b[i]. p should // be prime. /**************************************************************************\ Arithmetic mod X^n It is required that n >= 0, otherwise an error is raised. \**************************************************************************/ void trunc(zz_pX& x, const zz_pX& a, long n); // x = a % X^n zz_pX trunc(const zz_pX& a, long n); void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n); zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n); // x = a * b % X^n void SqrTrunc(zz_pX& x, const zz_pX& a, long n); zz_pX SqrTrunc(const zz_pX& a, long n); // x = a^2 % X^n void InvTrunc(zz_pX& x, const zz_pX& a, long n); zz_pX InvTrunc(const zz_pX& a, long n); // computes x = a^{-1} % X^n. Must have ConstTerm(a) invertible. /**************************************************************************\ Modular Arithmetic (without pre-conditioning) Arithmetic mod f. All inputs and outputs are polynomials of degree less than deg(f), and deg(f) > 0. NOTE: if you want to do many computations with a fixed f, use the zz_pXModulus data structure and associated routines below for better performance. \**************************************************************************/ void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f); zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f); // x = (a * b) % f void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX SqrMod(const zz_pX& a, const zz_pX& f); // x = a^2 % f void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX MulByXMod(const zz_pX& a, const zz_pX& f); // x = (a * X) mod f void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f); zz_pX InvMod(const zz_pX& a, const zz_pX& f); // x = a^{-1} % f, error is a is not invertible long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f); // if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise, // returns 1 and sets x = (a, f) // for modular exponentiation, see below /**************************************************************************\ Modular Arithmetic with Pre-Conditioning If you need to do a lot of arithmetic modulo a fixed f, build zz_pXModulus F for f. This pre-computes information about f that speeds up subsequent computations. Required: deg(f) > 0 and LeadCoeff(f) invertible. As an example, the following routine computes the product modulo f of a vector of polynomials. #include "zz_pX.h" void product(zz_pX& x, const vec_zz_pX& v, const zz_pX& f) { zz_pXModulus F(f); zz_pX res; res = 1; long i; for (i = 0; i < v.length(); i++) MulMod(res, res, v[i], F); x = res; } Note that automatic conversions are provided so that a zz_pX can be used wherever a zz_pXModulus is required, and a zz_pXModulus can be used wherever a zz_pX is required. \**************************************************************************/ class zz_pXModulus { public: zz_pXModulus(); // initially in an unusable state ~zz_pXModulus(); zz_pXModulus(const zz_pXModulus&); // copy zz_pXModulus& operator=(const zz_pXModulus&); // assignment zz_pXModulus(const zz_pX& f); // initialize with f, deg(f) > 0 operator const zz_pX& () const; // read-only access to f, implicit conversion operator const zz_pX& val() const; // read-only access to f, explicit notation }; void build(zz_pXModulus& F, const zz_pX& f); // pre-computes information about f and stores it in F. // Note that the declaration zz_pXModulus F(f) is equivalent to // zz_pXModulus F; build(F, f). // In the following, f refers to the polynomial f supplied to the // build routine, and n = deg(f). long deg(const zz_pXModulus& F); // return deg(f) void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F); // x = (a * b) % f; deg(a), deg(b) < n void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F); // x = a^2 % f; deg(a) < n void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F); zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F); void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F); zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F); // x = a^e % f; deg(a) < n (e may be negative) void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F); zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F); void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F); zz_pX PowerXMod(long e, const zz_pXModulus& F); // x = X^e % f (e may be negative) void PowerXPlusAMod(zz_pX& x, const zz_p& a, const ZZ& e, const zz_pXModulus& F); zz_pX PowerXPlusAMod(const zz_p& a, const ZZ& e, const zz_pXModulus& F); void PowerXPlusAMod(zz_pX& x, const zz_p& a, long e, const zz_pXModulus& F); zz_pX PowerXPlusAMod(const zz_p& a, long e, const zz_pXModulus& F); // x = (X + a)^e % f (e may be negative) void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F); // x = a % f void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F); // q = a/f, r = a%f void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F); // q = a/f // operator notation: zz_pX operator/(const zz_pX& a, const zz_pXModulus& F); zz_pX operator%(const zz_pX& a, const zz_pXModulus& F); zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F); zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F); /**************************************************************************\ More Pre-Conditioning If you need to compute a * b % f for a fixed b, but for many a's, it is much more efficient to first build a zz_pXMultiplier B for b, and then use the MulMod routine below. Here is an example that multiplies each element of a vector by a fixed polynomial modulo f. #include "zz_pX.h" void mul(vec_zz_pX& v, const zz_pX& b, const zz_pX& f) { zz_pXModulus F(f); zz_pXMultiplier B(b, F); long i; for (i = 0; i < v.length(); i++) MulMod(v[i], v[i], B, F); } Note that a (trivial) conversion operator from zz_pXMultiplier to zz_pX is provided, so that a zz_pXMultiplier can be used in a context where a zz_pX is required. \**************************************************************************/ class zz_pXMultiplier { public: zz_pXMultiplier(); // initially zero zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F); // initializes with b mod F, where deg(b) < deg(F) zz_pXMultiplier(const zz_pXMultiplier&); zz_pXMultiplier& operator=(const zz_pXMultiplier&); ~zz_pXMultiplier(); const zz_pX& val() const; // read-only access to b }; void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F); // pre-computes information about b and stores it in B; deg(b) < // deg(F) void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // x = (a * b) % F; deg(a) < deg(F) /**************************************************************************\ vectors of zz_pX's \**************************************************************************/ typedef Vec vec_zz_pX; // backward compatibility /**************************************************************************\ Modular Composition Modular composition is the problem of computing g(h) mod f for polynomials f, g, and h. The algorithm employed is that of Brent & Kung (Fast algorithms for manipulating formal power series, JACM 25:581-595, 1978), which uses O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar operations. \**************************************************************************/ void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F); // x = g(h) mod f; deg(h) < n void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1,2), deg(h) < n. void CompMod3(zz_pX& x1, zz_pX& x2, zz_pX& x3, const zz_pX& g1, const zz_pX& g2, const zz_pX& g3, const zz_pX& h, const zz_pXModulus& F); // xi = gi(h) mod f (i=1..3), deg(h) < n /**************************************************************************\ Composition with Pre-Conditioning If a single h is going to be used with many g's then you should build a zz_pXArgument for h, and then use the compose routine below. The routine build computes and stores h, h^2, ..., h^m mod f. After this pre-computation, composing a polynomial of degree roughly n with h takes n/m multiplies mod f, plus n^2 scalar multiplies. Thus, increasing m increases the space requirement and the pre-computation time, but reduces the composition time. \**************************************************************************/ struct zz_pXArgument { vec_zz_pX H; }; void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); // Pre-Computes information about h. m > 0, deg(h) < n void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H, const zz_pXModulus& F); extern thread_local long zz_pXArgBound; // Initially 0. If this is set to a value greater than zero, then // composition routines will allocate a table of no than about // zz_pXArgBound KB. Setting this value affects all compose routines // and the power projection and minimal polynomial routines below, // and indirectly affects many routines in zz_pXFactoring. /**************************************************************************\ power projection routines \**************************************************************************/ void project(zz_p& x, const zz_pVector& a, const zz_pX& b); zz_p project(const zz_pVector& a, const zz_pX& b); // x = inner product of a with coefficient vector of b void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pX& h, const zz_pXModulus& F); // Computes the vector // project(a, 1), project(a, h), ..., project(a, h^{k-1} % f). // This operation is the "transpose" of the modular composition operation. // Input and output may have "high order" zeroes stripped. void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); vec_zz_p ProjectPowers(const vec_zz_p& a, long k, const zz_pXArgument& H, const zz_pXModulus& F); // same as above, but uses a pre-computed zz_pXArgument void UpdateMap(vec_zz_p& x, const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); vec_zz_p UpdateMap(const vec_zz_p& a, const zz_pXMultiplier& B, const zz_pXModulus& F); // Computes the vector // project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f) // Restriction: a.length() <= deg(F). // This is "transposed" MulMod by B. // Input vector may have "high order" zeroes striped. // The output will always have high order zeroes stripped. /**************************************************************************\ Faster Composition and Projection with Pre-Conditioning A new, experimental version of composition with preconditioning. This interface was introduced in NTL v10.2.0, and it should be considered a preliminary interface and subject to change. The class zz_pXNewArgument is similar to zz_pXArgument, but with a different internal layout. Copy constructor and assignment work. Note that all NTL modular composition and power projection routines, as well as other routines that use modular composition power projection internally, now use this new class. Note also that these routines do not pay any attention to the zz_pXArgBound variable. \**************************************************************************/ class zz_pXNewArgument { // ... }; void build(zz_pXNewArgument& H, const zz_pX& h, const zz_pXModulus& F, long m); // same functionality as the corresponding zz_pXArgument-based routine void CompMod(zz_pX& x, const zz_pX& g, const zz_pXNewArgument& H, const zz_pXModulus& F); // same functionality as the corresponding zz_pXArgument-based routine void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k, const zz_pXNewArgument& H, const zz_pXModulus& F); // same functionality as the corresponding zz_pXArgument-based routine /**************************************************************************\ Minimum Polynomials These routines should be used with prime p. All of these routines implement the algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397, 1995], based on transposed modular composition and the Berlekamp/Massey algorithm. \**************************************************************************/ void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m); // computes the minimum polynomial of a linealy generated sequence; m // is a bound on the degree of the polynomial; required: a.length() >= // 2*m void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m); void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F); // computes the monic minimal polynomial if (g mod f). m = a bound on // the degree of the minimal polynomial; in the second version, this // argument defaults to n. The algorithm is probabilistic, always // returns a divisor of the minimal polynomial, and returns a proper // divisor with probability at most m/p. void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m); void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F); // same as above, but guarantees that result is correct void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m); zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F, long m); void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F); zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F); // same as above, but assumes that f is irreducible, or at least that // the minimal poly of g is itself irreducible. The algorithm is // deterministic (and is always correct). /**************************************************************************\ Traces, norms, resultants These routines should be used with prime p. \**************************************************************************/ void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F); zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F); void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f); zz_p TraceMod(const zz_pX& a, const zz_pXModulus& f); // x = Trace(a mod f); deg(a) < deg(f) void TraceVec(vec_zz_p& S, const zz_pX& f); vec_zz_p TraceVec(const zz_pX& f); // S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f) // The above routines implement the asymptotically fast trace // algorithm from [von zur Gathen and Shoup, Computational Complexity, // 1992]. void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f); zz_p NormMod(const zz_pX& a, const zz_pX& f); // x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f) void resultant(zz_p& x, const zz_pX& a, const zz_pX& b); zz_pX resultant(zz_p& x, const zz_pX& a, const zz_pX& b); // x = resultant(a, b) void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f); zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f); // g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) < // deg(f). This routine works for arbitrary f. For irreducible f, // is it faster to use IrredPolyMod, and then exponentiate as // necessary, since in this case the characterstic polynomial // is a power of the minimal polynomial. /**************************************************************************\ Miscellany \**************************************************************************/ void clear(zz_pX& x) // x = 0 void set(zz_pX& x); // x = 1 void zz_pX::kill(); // f.kill() sets f to 0 and frees all memory held by f. Equivalent to // f.rep.kill(). zz_pX::zz_pX(INIT_SIZE_TYPE, long n); // zz_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated // for n coefficients static const zz_pX& zero(); // zz_pX::zero() is a read-only reference to 0 void swap(zz_pX& x, zz_pX& y); // swap x and y (via "pointer swapping") zz_pX::zz_pX(long i, zz_p c); zz_pX::zz_pX(long i, long c); // initialize to c*X^i, provided for backward compatibility ntl-11.5.1/doc/lzz_pXFactoring.txt0000644417616742025610000001416014064716023020611 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: zz_pXFactoring SUMMARY: Routines are provided for factorization of polynomials over zz_p, as well as routines for related problems such as testing irreducibility and constructing irreducible polynomials of given degree. \**************************************************************************/ #include "zz_pX.h" #include "pair_zz_pX_long.h" void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f); vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f); // Performs square-free decomposition. f must be monic. If f = // prod_i g_i^i, then u is set to a lest of pairs (g_i, i). The list // is is increasing order of i, with trivial terms (i.e., g_i = 1) // deleted. void FindRoots(vec_zz_p& x, const zz_pX& f); vec_zz_p FindRoots(const zz_pX& f); // f is monic, and has deg(f) distinct roots. returns the list of // roots void FindRoot(zz_p& root, const zz_pX& f); zz_p FindRoot(const zz_pX& f); // finds a single root of f. assumes that f is monic and splits into // distinct linear factors void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX SFBerlekamp(const zz_pX& f, long verbose=0); // Assumes f is square-free and monic. returns list of factors of f. // Uses "Berlekamp" approach, as described in detail in [Shoup, // J. Symbolic Comp. 20:363-397, 1995]. void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SFBerlekamp. void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h, long verbose=0); vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h, long verbose=0); // This computes a distinct-degree factorization. The input must be // monic and square-free. factors is set to a list of pairs (g, d), // where g is the product of all irreducible factors of f of degree d. // Only nontrivial pairs (i.e., g != 1) are included. The polynomial // h is assumed to be equal to X^p mod f. This routine implements the // baby step/giant step algorithm of [Kaltofen and Shoup, STOC 1995], // further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995]. void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& h, long d, long verbose=0); vec_zz_pX EDF(const zz_pX& f, const zz_pX& h, long d, long verbose=0); // Performs equal-degree factorization. f is monic, square-free, and // all irreducible factors have same degree. h = X^p mod f. d = // degree of irreducible factors of f. This routine implements the // algorithm of [von zur Gathen and Shoup, Computational Complexity // 2:187-224, 1992] void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX RootEDF(const zz_pX& f, long verbose=0); // EDF for d==1 void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0); vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0); // Assumes f is monic and square-free. returns list of factors of f. // Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and // EDF above. void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f, long verbose=0); vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0); // returns a list of factors, with multiplicities. f must be monic. // Calls SquareFreeDecomp and SFCanZass. // NOTE: In most situations, you should use the CanZass factoring // routine, rather than Berlekamp: it is faster and uses less space. void mul(zz_pX& f, const vec_pair_zz_pX_long& v); zz_pX mul(const vec_pair_zz_pX_long& v); // multiplies polynomials, with multiplicities /**************************************************************************\ Irreducible Polynomials \**************************************************************************/ long ProbIrredTest(const zz_pX& f, long iter=1); // performs a fast, probabilistic irreduciblity test. The test can // err only if f is reducible, and the error probability is bounded by // p^{-iter}. This implements an algorithm from [Shoup, J. Symbolic // Comp. 17:371-391, 1994]. long DetIrredTest(const zz_pX& f); // performs a recursive deterministic irreducibility test. Fast in // the worst-case (when input is irreducible). This implements an // algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994]. long IterIrredTest(const zz_pX& f); // performs an iterative deterministic irreducibility test, based on // DDF. Fast on average (when f has a small factor). void BuildIrred(zz_pX& f, long n); zz_pX BuildIrred_zz_pX(long n); // Build a monic irreducible poly of degree n. void BuildRandomIrred(zz_pX& f, const zz_pX& g); zz_pX BuildRandomIrred(const zz_pX& g); // g is a monic irreducible polynomial. Constructs a random monic // irreducible polynomial f of the same degree. long ComputeDegree(const zz_pX& h, const zz_pXModulus& F); // f is assumed to be an "equal degree" polynomial. h = X^p mod f. // The common degree of the irreducible factors of f is computed This // routine is useful in counting points on elliptic curves long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F); // same as above, but uses a slightly faster probabilistic algorithm. // The return value may be 0 or may be too big, but for large p // (relative to n), this happens with very low probability. void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& h); zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F, const zz_pX& h); // w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h = // X^q mod f, q a power of p. This routine implements an algorithm // from [von zur Gathen and Shoup, Computational Complexity 2:187-224, // 1992] void PowerCompose(zz_pX& w, const zz_pX& h, long d, const zz_pXModulus& F); zz_pX PowerCompose(const zz_pX& h, long d, const zz_pXModulus& F); // w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q // a power of p. This routine implements an algorithm from [von zur // Gathen and Shoup, Computational Complexity 2:187-224, 1992] ntl-11.5.1/doc/mat_GF2.txt0000644417616742025610000001065714064716023016714 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_GF2 SUMMARY: Defines the class mat_GF2. \**************************************************************************/ #include #include typedef Mat mat_GF2; // backward compatibility void conv(mat_GF2& X, const vec_vec_GF2& A); mat_GF2 to_mat_GF2(const vec_vec_GF2& A); // convert a vector of vec_GF2's to a matrix // procedural arithmetic routines: void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A + B void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A - B = A + B void negate(mat_GF2& X, const mat_GF2& A); // X = -A = A void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B); // X = A * B void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b); // x = A * b void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B); // x = a * B void mul(mat_GF2& X, const mat_GF2& A, GF2 b); void mul(mat_GF2& X, const mat_GF2& A, long b); // X = A * b void mul(mat_GF2& X, GF2 a, const mat_GF2& B); void mul(mat_GF2& X, long a, const mat_GF2& B); // X = a * B void determinant(GF2& d, const mat_GF2& A); GF2 determinant(const mat_GF2& A); // d = determinant of A void transpose(mat_GF2& X, const mat_GF2& A); mat_GF2 transpose(const mat_GF2& A); // X = transpose of A void solve(GF2& d, vec_GF2& x, const mat_GF2& A, const vec_GF2& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves x*A = b. void solve(GF2& d, const mat_GF2& A, vec_GF2& x, const vec_GF2& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(GF2& d, mat_GF2& X, const mat_GF2& A); // A is an n x n matrix. Computes d = det(A). If d != 0, // computes X = A^{-1}. void sqr(mat_GF2& X, const mat_GF2& A); mat_GF2 sqr(const mat_GF2& A); // X = A*A void inv(mat_GF2& X, const mat_GF2& A); mat_GF2 inv(const mat_GF2& A); // X = A^{-1}; error is raised if A is singular void power(mat_GF2& X, const mat_GF2& A, const ZZ& e); mat_GF2 power(const mat_GF2& A, const ZZ& e); void power(mat_GF2& X, const mat_GF2& A, long e); mat_GF2 power(const mat_GF2& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_GF2& X, long n); mat_GF2 ident_mat_GF2(long n); // X = n x n identity matrix long IsIdent(const mat_GF2& A, long n); // test if A is n x n identity matrix void diag(mat_GF2& X, long n, GF2 d); mat_GF2 diag(long n, GF2 d); // X = n x n diagonal matrix with diagonal element d long IsDiag(const mat_GF2& A, long n, long d); // test if X is an n x n diagonal matrix with diagonal element (d mod 2) void random(mat_GF2& x, long n, long m); // x = random n x m matrix mat_GF2 random_mat_GF2(long n, long m); long gauss(mat_GF2& M); long gauss(mat_GF2& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_GF2& X, const mat_GF2& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_GF2& X, const mat_GF2& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_GF2& X); // X = 0 (dimension unchanged) long IsZero(const mat_GF2& A); // test if A is the zero matrix (any dimension) // arithmetic operator notation: mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b); mat_GF2 operator-(const mat_GF2& a); // matrix/scalar multiplication: mat_GF2 operator*(const mat_GF2& a, GF2 b); mat_GF2 operator*(const mat_GF2& a, long b); mat_GF2 operator*(GF2 a, const mat_GF2& b); mat_GF2 operator*(long a, const mat_GF2& b); // matrix/vector multiplication: vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b); vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b); // assignment operator notation: mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a); mat_GF2& operator*=(mat_GF2& x, GF2 a); mat_GF2& operator*=(mat_GF2& x, long a); vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a); ntl-11.5.1/doc/mat_GF2E.txt0000644417616742025610000001122514064716023017011 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_GF2E SUMMARY: Defines the class mat_GF2E. \**************************************************************************/ #include #include typedef Mat mat_GF2E; // backward compatibility void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A + B void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A - B = A + B void negate(mat_GF2E& X, const mat_GF2E& A); // X = - A = A void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B); // X = A * B void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); // x = A * b void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B); // x = a * B void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b); void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b); void mul(mat_GF2E& X, const mat_GF2E& A, long b); // X = A * b void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B); void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B); void mul(mat_GF2E& X, long a, const mat_GF2E& B); // X = a * B void determinant(GF2E& d, const mat_GF2E& A); GF2E determinant(const mat_GF2E& a); // d = determinant(A) void transpose(mat_GF2E& X, const mat_GF2E& A); mat_GF2E transpose(const mat_GF2E& A); // X = transpose of A void solve(GF2E& d, vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves x*A = b. void solve(GF2E& d, const mat_GF2E& A, vec_GF2E& x, const vec_GF2E& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_GF2E& X, const mat_GF2E& A); mat_GF2E sqr(const mat_GF2E& A); // X = A*A void inv(mat_GF2E& X, const mat_GF2E& A); mat_GF2E inv(const mat_GF2E& A); // X = A^{-1}; error is raised if A is singular void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e); mat_GF2E power(const mat_GF2E& A, const ZZ& e); void power(mat_GF2E& X, const mat_GF2E& A, long e); mat_GF2E power(const mat_GF2E& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_GF2E& X, long n); mat_GF2E ident_mat_GF2E(long n); // X = n x n identity matrix long IsIdent(const mat_GF2E& A, long n); // test if A is the n x n identity matrix void diag(mat_GF2E& X, long n, const GF2E& d); mat_GF2E diag(long n, const GF2E& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_GF2E& A, long n, const GF2E& d); // test if X is an n x n diagonal matrix with d on diagonal void random(mat_GF2E& x, long n, long m); // x = random n x m matrix mat_GF2E random_mat_GF2E(long n, long m); long gauss(mat_GF2E& M); long gauss(mat_GF2E& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_GF2E& X, const mat_GF2E& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_GF2E& X, const mat_GF2E& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_GF2E& a); // x = 0 (dimension unchanged) long IsZero(const mat_GF2E& a); // test if a is the zero matrix (any dimension) // operator notation: mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b); mat_GF2E operator-(const mat_GF2E& a); // matrix/scalar multiplication: mat_GF2E operator*(const mat_GF2E& a, const GF2E& b); mat_GF2E operator*(const mat_GF2E& a, GF2 b); mat_GF2E operator*(const mat_GF2E& a, long b); mat_GF2E operator*(const GF2E& a, const mat_GF2E& b); mat_GF2E operator*(GF2 a, const mat_GF2E& b); mat_GF2E operator*(long a, const mat_GF2E& b); // matrix/vector multiplication: vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b); vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b); // assignment operator notation: mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a); mat_GF2E& operator*=(mat_GF2E& x, GF2 a); mat_GF2E& operator*=(mat_GF2E& x, long a); vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a); ntl-11.5.1/doc/mat_RR.txt0000644417616742025610000000647314064716023016662 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_RR SUMMARY: Defines the class mat_RR. \**************************************************************************/ #include #include typedef Mat mat_RR; // backward compatibility void add(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A + B void sub(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A - B void negate(mat_RR& X, const mat_RR& A); // X = - A void mul(mat_RR& X, const mat_RR& A, const mat_RR& B); // X = A * B void mul(vec_RR& x, const mat_RR& A, const vec_RR& b); // x = A * b void mul(vec_RR& x, const vec_RR& a, const mat_RR& B); // x = a * B void mul(mat_RR& X, const mat_RR& A, const RR& b); void mul(mat_RR& X, const mat_RR& A, double b); // X = A * b void mul(mat_RR& X, const RR& a, const mat_RR& B); void mul(mat_RR& X, double a, const mat_RR& B); // X = a * B void determinant(RR& d, const mat_RR& A); RR determinant(const mat_RR& A); // d = determinant(A) void transpose(mat_RR& X, const mat_RR& A); mat_RR transpose(const mat_RR& A); // X = transpose of A void solve(RR& d, vec_RR& X, const mat_RR& A, const vec_RR& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void inv(RR& d, mat_RR& X, const mat_RR& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_RR& X, const mat_RR& A); mat_RR sqr(const mat_RR& A); // X = A*A void inv(mat_RR& X, const mat_RR& A); mat_RR inv(const mat_RR& A); // X = A^{-1}; error is raised if A is singular void power(mat_RR& X, const mat_RR& A, const ZZ& e); mat_RR power(const mat_RR& A, const ZZ& e); void power(mat_RR& X, const mat_RR& A, long e); mat_RR power(const mat_RR& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_RR& X, long n); mat_RR ident_mat_RR(long n); // X = n x n identity matrix long IsIdent(const mat_RR& A, long n); // test if A is the n x n identity matrix void diag(mat_RR& X, long n, const RR& d); mat_RR diag(long n, const RR& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_RR& A, long n, const RR& d); // test if X is an n x n diagonal matrix with d on diagonal // miscellaneous: void clear(mat_RR& a); // x = 0 (dimension unchanged) long IsZero(const mat_RR& a); // test if a is the zero matrix (any dimension) // operator notation: mat_RR operator+(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a, const mat_RR& b); mat_RR operator*(const mat_RR& a, const mat_RR& b); mat_RR operator-(const mat_RR& a); // matrix/scalar multiplication: mat_RR operator*(const mat_RR& a, const RR& b); mat_RR operator*(const mat_RR& a, double b); mat_RR operator*(const RR& a, const mat_RR& b); mat_RR operator*(double a, const mat_RR& b); // matrix/vector multiplication: vec_RR operator*(const mat_RR& a, const vec_RR& b); vec_RR operator*(const vec_RR& a, const mat_RR& b); // assignment operator notation: mat_RR& operator+=(mat_RR& x, const mat_RR& a); mat_RR& operator-=(mat_RR& x, const mat_RR& a); mat_RR& operator*=(mat_RR& x, const mat_RR& a); mat_RR& operator*=(mat_RR& x, const RR& a); mat_RR& operator*=(mat_RR& x, double a); vec_RR& operator*=(vec_RR& x, const mat_RR& a); ntl-11.5.1/doc/mat_ZZ.txt0000644417616742025610000001136614064716023016677 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_ZZ SUMMARY: Defines the class mat_ZZ. \**************************************************************************/ #include #include typedef Mat mat_ZZ; // backward compatibility void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A + B void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A - B void negate(mat_ZZ& X, const mat_ZZ& A); // X = - A void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B); // X = A * B void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); // x = A * b void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B); // x = a * B void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b); void mul(mat_ZZ& X, const mat_ZZ& A, long b); // X = A * b void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B); void mul(mat_ZZ& X, long a, const mat_ZZ& B); // X = a * B void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0); ZZ determinant(const mat_ZZ& a, long deterministic=0); // d = determinant(A). If !deterministic, a randomized strategy may // be used that errs with probability at most 2^{-80}. void solve(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b, long deterministic=0) // computes d = determinant(A) and solves x*A = b*d if d != 0; A must // be a square matrix and have compatible dimensions with b. If // !deterministic, the computation of d may use a randomized strategy // that errs with probability 2^{-80}. void solve1(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b); // A must be a square matrix. // If A is singular, this routine sets d = 0 and returns. // Otherwise, it computes d, x such that x*A == b*d, // such that d > 0 and minimal. // Note that d is a positive divisor of the determinant, // and is not in general equal to the determinant. // The routine is deterministic, and uses a Hensel lifting strategy. // For backward compatability, there is also a routine called // HenselSolve1 that simply calls solve1. void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0); // computes d = determinant(A) and solves X*A = I*d if d != 0; A must // be a square matrix. If !deterministic, the computation of d may // use a randomized strategy that errs with probability 2^{-80}. // NOTE: See LLL.txt for routines that compute the kernel and // image of an integer matrix. // NOTE: See HNF.txt for a routine that computes Hermite Normal Forms. void sqr(mat_ZZ& X, const mat_ZZ& A); mat_ZZ sqr(const mat_ZZ& A); // X = A*A void inv(mat_ZZ& X, const mat_ZZ& A); mat_ZZ inv(const mat_ZZ& A); // X = A^{-1}; error is raised if |det(A)| != 1. void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e); mat_ZZ power(const mat_ZZ& A, const ZZ& e); void power(mat_ZZ& X, const mat_ZZ& A, long e); mat_ZZ power(const mat_ZZ& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ& X, long n); mat_ZZ ident_mat_ZZ(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ& X, long n, const ZZ& d); mat_ZZ diag(long n, const ZZ& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ& A, long n, const ZZ& d); // test if X is an n x n diagonal matrix with d on diagonal void transpose(mat_ZZ& X, const mat_ZZ& A); mat_ZZ transpose(const mat_ZZ& A); // X = transpose of A long CRT(mat_ZZ& a, ZZ& prod, const mat_zz_p& A); // Incremental Chinese Remaindering: If p is the current zz_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. // miscellaneous: void clear(mat_ZZ& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b); mat_ZZ operator-(const mat_ZZ& a); // matrix/scalar multiplication: mat_ZZ operator*(const mat_ZZ& a, const ZZ& b); mat_ZZ operator*(const mat_ZZ& a, long b); mat_ZZ operator*(const ZZ& a, const mat_ZZ& b); mat_ZZ operator*(long a, const mat_ZZ& b); // matrix/vector multiplication: vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b); vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b); // assignment operator notation: mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a); mat_ZZ& operator*=(mat_ZZ& x, long a); vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a); ntl-11.5.1/doc/mat_ZZ_p.txt0000644417616742025610000001063614064716023017215 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_ZZ_p SUMMARY: Defines the class mat_ZZ_p. \**************************************************************************/ #include #include typedef Mat mat_ZZ_p; // backward compatibility void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A + B void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A - B void negate(mat_ZZ_p& X, const mat_ZZ_p& A); // X = - A void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B); // X = A * B void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b); // x = A * b void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B); // x = a * B void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b); void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b); // X = A * b void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B); void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B); // X = a * B void determinant(ZZ_p& d, const mat_ZZ_p& A); ZZ_p determinant(const mat_ZZ_p& a); // d = determinant(A) void transpose(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p transpose(const mat_ZZ_p& A); // X = transpose of A void solve(ZZ_p& d, vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves x*A = b. void solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p sqr(const mat_ZZ_p& A); // X = A*A void inv(mat_ZZ_p& X, const mat_ZZ_p& A); mat_ZZ_p inv(const mat_ZZ_p& A); // X = A^{-1}; error is raised if A is singular void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e); mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e); void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e); mat_ZZ_p power(const mat_ZZ_p& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ_p& X, long n); mat_ZZ_p ident_mat_ZZ_p(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ_p& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ_p& X, long n, const ZZ_p& d); mat_ZZ_p diag(long n, const ZZ_p& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d); // test if X is an n x n diagonal matrix with d on diagonal void random(mat_ZZ_p& x, long n, long m); // x = random n x m matrix mat_ZZ_p random_mat_ZZ_p(long n, long m); long gauss(mat_ZZ_p& M); long gauss(mat_ZZ_p& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_ZZ_p& X, const mat_ZZ_p& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_ZZ_p& X, const mat_ZZ_p& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_ZZ_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator-(const mat_ZZ_p& a); // matrix/scalar multiplication: mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b); mat_ZZ_p operator*(const mat_ZZ_p& a, long b); mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b); mat_ZZ_p operator*(long a, const mat_ZZ_p& b); // matrix/vector multiplication: vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b); // assignment operator notation: mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a); mat_ZZ_p& operator*=(mat_ZZ_p& x, long a); vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a); ntl-11.5.1/doc/mat_ZZ_pE.txt0000644417616742025610000001147414064716023017323 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_ZZ_pE SUMMARY: Defines the class mat_ZZ_pE. \**************************************************************************/ #include #include typedef Mat mat_ZZ_pE; // backward compatibility void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A + B void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A - B void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A); // X = - A void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B); // X = A * B void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); // x = A * b void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B); // x = a * B void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b); void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b); // X = A * b void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B); void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B); // X = a * B void determinant(ZZ_pE& d, const mat_ZZ_pE& A); ZZ_pE determinant(const mat_ZZ_pE& a); // d = determinant(A) void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE transpose(const mat_ZZ_pE& A); // X = transpose of A void solve(ZZ_pE& d, vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves x*A = b. void solve(ZZ_pE& d, const mat_ZZ_pE& A, vec_ZZ_pE& x, const vec_ZZ_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE sqr(const mat_ZZ_pE& A); // X = A*A void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A); mat_ZZ_pE inv(const mat_ZZ_pE& A); // X = A^{-1}; error is raised if A is singular void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e); mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e); void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e); mat_ZZ_pE power(const mat_ZZ_pE& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_ZZ_pE& X, long n); mat_ZZ_pE ident_mat_ZZ_pE(long n); // X = n x n identity matrix long IsIdent(const mat_ZZ_pE& A, long n); // test if A is the n x n identity matrix void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d); mat_ZZ_pE diag(long n, const ZZ_pE& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d); // test if X is an n x n diagonal matrix with d on diagonal void random(mat_ZZ_pE& x, long n, long m); // x = random n x m matrix mat_ZZ_pE random_mat_ZZ_pE(long n, long m); long gauss(mat_ZZ_pE& M); long gauss(mat_ZZ_pE& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_ZZ_pE& X, const mat_ZZ_pE& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_ZZ_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_ZZ_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator-(const mat_ZZ_pE& a); // matrix/scalar multiplication: mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b); mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b); mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b); mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b); // matrix/vector multiplication: vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b); // assignment operator notation: mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a); mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a); ntl-11.5.1/doc/mat_lzz_p.txt0000644417616742025610000001600314064716023017463 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_zz_p SUMMARY: Defines the class mat_zz_p. Note that the modulus p need not be a prime, except as indicated below. IMPLEMENTATION NOTES: Starting with NTL version 9.7.0 (and 9.7.1), many of the routines here have been optimized to take better advantage of specific hardware features available on 64-bit Intel CPU's. Currently, the mul, inv, determinant, solve, gauss, kernel, and image routines are fastest for p up to 23-bits long (assuming the CPU supports AVX instructions). After that, performance degrades in three stages: stage 1: up to 28-bits; stage 2: up to 31-bits; stage 3: 32-bits and up. For primes up to 23-bits, AVX floating point instructions are used. After that, ordinary integer arithmetic is used. In a future version, I may exploit AVX2 integer instructions to get better stage 2 performance. And in the more distant future, AVX512 instructions will be used, when they become available. On older Intel machines, or non-Intel machines that have "long long" support, one still gets optimizations corresponding to the three stages above. On 32-bit machines, one still gets three stages, just with smaller crossover points. \**************************************************************************/ #include #include "vec_vec_zz_p.h" typedef Mat mat_zz_p; // backward compatibility void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A + B void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A - B void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B); // X = A * B void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b); // x = A * b void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B); // x = a * B void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b); void mul(mat_zz_p& X, const mat_zz_p& A, long b); // X = A * b void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B); void mul(mat_zz_p& X, long a, const mat_zz_p& B); // X = a * B void transpose(mat_zz_p& X, const mat_zz_p& A); mat_zz_p transpose(const mat_zz_p& A); // X = transpose of A void determinant(zz_p& d, const mat_zz_p& A); zz_p determinant(const mat_zz_p& a); // d = determinant(A) void solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves x*A = b (so x and b are treated as a row vectors). void solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void inv(mat_zz_p& X, const mat_zz_p& A); mat_zz_p inv(const mat_zz_p& A); // X = A^{-1}; error is raised if A is singular void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e); mat_zz_p power(const mat_zz_p& A, const ZZ& e); void power(mat_zz_p& X, const mat_zz_p& A, long e); mat_zz_p power(const mat_zz_p& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). // NOTE: the routines determinant, solve, inv, and power (with negative // exponent) all require that the modulus p is prime: during elimination, if a // non-zero pivot element does not have an inverse, and error is raised. The // following "relaxed" versions of these routines will also work with prime // powers, if the optional parameter relax is true (which is the default). // However, note that in these relaxed routines, if a computed determinant // value is zero, this may not be the true determinant: all that you can assume // is that the true determinant is not invertible mod p. If the parameter // relax==false, then these routines behave identically to their "unrelaxed" // counterparts. void relaxed_determinant(zz_p& d, const mat_zz_p& A, bool relax=true); zz_p relaxed_determinant(const mat_zz_p& a, bool relax=true); void relaxed_solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b, bool relax=true); void relaxed_solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b, bool relax=true); void relaxed_inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax=true); void relaxed_inv(mat_zz_p& X, const mat_zz_p& A, bool relax=true); mat_zz_p relaxed_inv(const mat_zz_p& A, bool relax=true); void relaxed_power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e, bool relax=true); mat_zz_p relaxed_power(const mat_zz_p& A, const ZZ& e, bool relax=true); void relaxed_power(mat_zz_p& X, const mat_zz_p& A, long e, bool relax=true); mat_zz_p relaxed_power(const mat_zz_p& A, long e, bool relax=true); void sqr(mat_zz_p& X, const mat_zz_p& A); mat_zz_p sqr(const mat_zz_p& A); // X = A*A void ident(mat_zz_p& X, long n); mat_zz_p ident_mat_zz_p(long n); // X = n x n identity matrix long IsIdent(const mat_zz_p& A, long n); // test if A is the n x n identity matrix void diag(mat_zz_p& X, long n, zz_p d); mat_zz_p diag(long n, zz_p d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_zz_p& A, long n, zz_p d); // test if X is an n x n diagonal matrix with d on diagonal void random(mat_zz_p& x, long n, long m); // x = random n x m matrix mat_zz_p random_mat_zz_p(long n, long m); long gauss(mat_zz_p& M); long gauss(mat_zz_p& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_zz_p& X, const mat_zz_p& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_zz_p& X, const mat_zz_p& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // NOTE: the gauss, image, and kernel routines all require that // the modulus p is prime. // miscellaneous: void clear(mat_zz_p& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_p& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b); mat_zz_p operator-(const mat_zz_p& a); // matrix/scalar multiplication: mat_zz_p operator*(const mat_zz_p& a, zz_p b); mat_zz_p operator*(const mat_zz_p& a, long b); mat_zz_p operator*(zz_p a, const mat_zz_p& b); mat_zz_p operator*(long a, const mat_zz_p& b); // matrix/vector multiplication: vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b); vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b); // assignment operator notation: mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a); mat_zz_p& operator*=(mat_zz_p& x, zz_p a); mat_zz_p& operator*=(mat_zz_p& x, long a); vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a); ntl-11.5.1/doc/mat_lzz_pE.txt0000644417616742025610000001147614064716023017601 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_zz_pE SUMMARY: Defines the class mat_zz_pE. \**************************************************************************/ #include #include typedef Mat mat_zz_pE; // backward compatibility void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A + B void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A - B void negate(mat_zz_pE& X, const mat_zz_pE& A); // X = - A void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B); // X = A * B void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); // x = A * b void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B); // x = a * B void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b); void mul(mat_zz_pE& X, const mat_zz_pE& A, long b); // X = A * b void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B); void mul(mat_zz_pE& X, long a, const mat_zz_pE& B); // X = a * B void determinant(zz_pE& d, const mat_zz_pE& A); zz_pE determinant(const mat_zz_pE& a); // d = determinant(A) void transpose(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE transpose(const mat_zz_pE& A); // X = transpose of A void solve(zz_pE& d, vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = // determinant(A). If d != 0, solves x*A = b. void solve(zz_pE& d, const mat_zz_pE& A, vec_zz_pE& x, const vec_zz_pE& b); // A is an n x n matrix, b is a length n vector. Computes d = determinant(A). // If d != 0, solves A*x = b (so x and b are treated as a column vectors). void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A); // A is an n x n matrix. Computes d = determinant(A). If d != 0, // computes X = A^{-1}. void sqr(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE sqr(const mat_zz_pE& A); // X = A*A void inv(mat_zz_pE& X, const mat_zz_pE& A); mat_zz_pE inv(const mat_zz_pE& A); // X = A^{-1}; error is raised if A is singular void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e); mat_zz_pE power(const mat_zz_pE& A, const ZZ& e); void power(mat_zz_pE& X, const mat_zz_pE& A, long e); mat_zz_pE power(const mat_zz_pE& A, long e); // X = A^e; e may be negative (in which case A must be nonsingular). void ident(mat_zz_pE& X, long n); mat_zz_pE ident_mat_zz_pE(long n); // X = n x n identity matrix long IsIdent(const mat_zz_pE& A, long n); // test if A is the n x n identity matrix void diag(mat_zz_pE& X, long n, const zz_pE& d); mat_zz_pE diag(long n, const zz_pE& d); // X = n x n diagonal matrix with d on diagonal long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d); // test if X is an n x n diagonal matrix with d on diagonal void random(mat_zz_pE& x, long n, long m); // x = random n x m matrix mat_zz_pE random_mat_zz_pE(long n, long m); long gauss(mat_zz_pE& M); long gauss(mat_zz_pE& M, long w); // Performs unitary row operations so as to bring M into row echelon // form. If the optional argument w is supplied, stops when first w // columns are in echelon form. The return value is the rank (or the // rank of the first w columns). void image(mat_zz_pE& X, const mat_zz_pE& A); // The rows of X are computed as basis of A's row space. X is is row // echelon form void kernel(mat_zz_pE& X, const mat_zz_pE& A); // Computes a basis for the kernel of the map x -> x*A. where x is a // row vector. // miscellaneous: void clear(mat_zz_pE& a); // x = 0 (dimension unchanged) long IsZero(const mat_zz_pE& a); // test if a is the zero matrix (any dimension) // operator notation: mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator-(const mat_zz_pE& a); // matrix/scalar multiplication: mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b); mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b); mat_zz_pE operator*(const mat_zz_pE& a, long b); mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b); mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b); mat_zz_pE operator*(long a, const mat_zz_pE& b); // matrix/vector multiplication: vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b); // assignment operator notation: mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a); mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a); mat_zz_pE& operator*=(mat_zz_pE& x, long a); vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a); ntl-11.5.1/doc/mat_poly_ZZ.txt0000644417616742025610000000060714064716023017736 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_poly_ZZ SUMMARY: Routine for computing the characteristic polynomial of a matrix over ZZ. \**************************************************************************/ #include #include void CharPoly(ZZX& f, const mat_ZZ& M); // f = characteristic polynomial of M ntl-11.5.1/doc/mat_poly_ZZ_p.txt0000644417616742025610000000063014064716023020251 0ustar gid-shoupvpug-gid-shoupv /*****************************************************************************\ MODULE: mat_poly_ZZ_p SUMMARY: Routine for computing the characteristic polynomial of a matrix over ZZ_p. \*****************************************************************************/ #include #include void CharPoly(ZZ_pX& f, const mat_ZZ_p& M); // f = characteristic polynomial of M ntl-11.5.1/doc/mat_poly_lzz_p.txt0000644417616742025610000000061314064716023020526 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: mat_poly_zz_p SUMMARY: Routine for computing the characteristic polynomial of a matrix over zz_p. \**************************************************************************/ #include "mat_zz_p.h" #include "zz_pX.h" void CharPoly(zz_pX& f, const mat_zz_p& M); // f = characteristic polynomial of M ntl-11.5.1/doc/matrix.txt0000644417616742025610000001256114064716023016775 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: matrix SUMMARY: Matrix templates. The declaration Mat M; creates a 0 x 0 matrix. We can make it have 10 rows and 20 columns like this: M.SetDims(10, 20); A row can be accessed as M[i], indexing from 0, or as M(i), indexing from 1. A matrix entry can be accessed as M[i][j], indexing from 0, or as M(i, j), indexing from 1. A matrix is represented as a Vec< Vec >: a vector of rows, where each row is a Vec. Any attempt to resize one of the rows so as to create a non-rectangular matrix will result in a run-time error. The dimensions of an existing matrix may be changed. If the number of columns does not change, then the matrix is just "resized" like a vector, and no information is lost. Otherwise, if the number of columns changes, the matrix is completely destroyed, and a new matrix is created \**************************************************************************/ // EXCEPTIONS: all functions below do not throw any exceptions, // except as noted template class Mat { typedef typename Vec::value_type value_type; typedef typename Vec::reference reference; typedef typename Vec::const_reference const_reference; Mat(); // initially 0 x 0 Mat(const Mat& a); // copy constructor // EXCEPTIONS: may throw Mat& operator=(const Mat& a); // assignment // EXCEPTIONS: may throw, weak ES (but dimensions of LHS // will be either that of old LHS or RHS) ~Mat(); // destructor Mat(Mat&& other) noexcept; #ifndef NTL_DISABLE_MOVE_ASSIGN Mat& operator=(Mat&& other) noexcept; #endif // move semantics (C++11 only) Mat(INIT_SIZE_TYPE, long n, long m); // Mat(INIT_SIZE, n, m) initializes an n x m matrix, invoking // the default constructor for T to initialize entries. // EXCEPTIONS: may throw void SetDims(long n, long m); // M.SetDims(n, m) makes M have dimension n x m. If the number of // columns (m) changes, previous storage is freed, and space for M // is reallocated and initialized; otherwise, more rows are // allocated as necessary (when number of rows increases), // excess rows are retained (when number of rows decreases), // and--importantly--the contents do not change. // EXCEPTIONS: strong ES (although underlying vector representation // may be reallocated) void kill(); free storage and make 0 x 0 long NumRows() const; // M.NumRows() returns the number of rows of M long NumCols() const; // M.NumCols() returns the number of columns of M Vec& operator[](long i); const Vec& operator[](long i) const; // access row i, initial index 0. // Even if one has read/write access to a row, any attempt // to change its length will raise an error. // EXCEPTIONS: may throw if range checking is turned on Vec& operator()(long i); const Vec& operator()(long i) const; // access row i, initial index 1. // Even if one has read/write access to a row, any attempt // to change its length will raise an error. // of this row will raise an error. // EXCEPTIONS: may throw if range checking is turned on reference operator()(long i, long j); const_reference operator()(long i, long j) const; // access element (i, j), both indices starting at 1 // EXCEPTIONS: may throw if range checking is turned on const_reference get(long i, long j) const; // access element (i, j), both indices starting at 0 // EXCEPTIONS: may throw if range checking is turned on void put(long i, long j, const T& a); // same as M[i].put(j, a) template void put(long i, long j, const U& a); // same as M[i].put(j, a) long position(const Vec& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position(a). long position1(const Vec& a) const; // returns index of a in matrix, or -1 if not present; // equivalent to rep(*this).position1(a). long alias(const Vec& a) const; // returns 1 if a aliases a row of the matrix, and 0 otherwise. void swap(Mat& other); // quick swap *this and other void move(Mat& other); // quick move other to *this }; template const Vec< Vec >& rep(const Mat& a); // read-only access to underlying representation template void swap(Mat& X, Mat& Y); // quick swap of X and Y template void MakeMatrix(Mat& x, const vec_vec_T& a); // copies a to x, checking that it is "rectangular" // EXCEPTIONS: may thow, weak ES (but dimensions of x either // remain unchanged or are set to the new dimensions implied by a) /**************************************************************************\ Input/Output \**************************************************************************/ template istream& operator>>(istream&, Mat&); // EXCEPTIONS: may throw, weak ES template ostream& operator<<(ostream&, const Mat&); // EXCEPTIONS: may throw, weak ES /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Mat& a, const Mat& b); template long operator!=(const Mat& a, const Mat& b); ntl-11.5.1/doc/pair.txt0000644417616742025610000000316014064716023016417 0ustar gid-shoupvpug-gid-shoupv/**************************************************************************\ MODULE: pair SUMMARY: Pair templates. The decalaration Pair p; creates a pair object using the default constructors for S and T. The member p.a is the first component (of type S) and the member p.b is the second component (of type T). \**************************************************************************/ #include template class Pair { public: S a; T b; Pair(); // default constructor...invokes default constructors for S and T Pair(const S& x, const T& y); // initialize with (x, y) ~Pair(); // destructor...invokes destructors for S and T // defaut copy and move constructors and assignment }; template Pair cons(const S& x, const T& y); // returns Pair(x, y) /**************************************************************************\ Input/Output The I/O format for a Pair is [a b] \**************************************************************************/ template istream& operator>>(istream&, Pair&); template ostream& operator<<(ostream&, const Pair&); /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Pair& x, const Pair& y); template long operator!=(const Pair& x, const Pair& y); ntl-11.5.1/doc/vector.txt0000644417616742025610000005364114064716023016777 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vector SUMMARY: Template class for dynamic-sized vectors. The declaration Vec v; creates a zero-length vector. To grow this vector to length n, execute v.SetLength(n) This causes space to be allocated for (at least) n elements, and also causes the default constructor for T to be called to initialize these elements. The current length of a vector is available as v.length(). Let n = v.length(). Calling v.SetLength(m) with m <= n sets the current length of v to m (but does not call any destructors or free any space). Calling v.SetLength(m) with m > n will allocate space and initialize as necessary, but will leave the values of the already allocated elements unchanged (although their addresses may change). If T has a user-defined default constructor, that is invoked. Otherwise, the new memory locations are "default initialized". In particular, this means that POD types may be uninitialized. v.MaxLength() is the largest value of n for which v.SetLength(n) was invoked, and is equal to the number of entries that have been initialized. v.SetMaxLength(n) will allocate space for and initialize up to n elements, without changing v.length(). When v's destructor is called, all constructed elements will be destructed, and all space will be relinquished. v.allocated() is the number of elements which have been allocated, which may be more than the number elements initialized. Note that if n <= v.allocated(), then v.SetLength(n) is guaranteed not to cause any memory allocation or movement of objects. Space is managed using malloc, realloc, and free. When a vector is grown, a bit more space may be allocated than was requested for efficiency reasons. Note that when a vector is grown, the objects in the vector may have moved, possibly creating dangling references to vector elements. One has to be especially careful of this when using vectors passed as reference parameters that may alias one another. ---------------------- IMPLEMENTATION DETAILS ---------------------- A Vec object is just a pointer to the first element of the array. There is a control block immediately before the first element that keeps track of several parameters: len -- the logical length of the array (returned by length()) init -- the number of elements constructed (returned ny MaxLength()) alloc -- the number of elements for which space has been allocated (returned by allocated()) fixed -- flag that indicates that the length is fixed (returned by fixed()) Note that 0 <= len <= init <- alloc --------------- SPECIALIZATIONS --------------- NTL currently defines an optimized specialization Vec. There are a few quirks to be aware of. See the documentation file for vec_GF2 for more details. --------------------- RANGE-BASED FOR LOOPS --------------------- NTL's vectors provide sufficient functionality to enable range-based for-loops (in C++11). The safest ways to use this functionality are to write: for (auto&& item : vec) { ... } // for read-only or read/write access or for (T item : vec) { ... } // for access via a copy This is especially true if vec may be of type Vec. Again, see the documentation file for vec_GF2 for more details. -------------- OTHER FEATURES -------------- The i-th vector element (counting from 0) is accessed as v[i]. If the macro NTL_RANGE_CHECK is defined, code is emitted to test if 0 <= i < v.length(). This check is not performed by default. For old-time FORTRAN programmers, the i-th vector element (counting from 1) is accessed as v(i). -------------------- REALLOCATION DETAILS -------------------- When a vector is resized and not enough space has been allocated, then a reallocation process takes place. There are several strategies which can be used, which we list here from least to most efficient. COPY AND DESTROY STRATEGY: This is the same strategy used by the STL prior to C++11. New memory is allocated, and each element of the vector is copied (using a copy constructor) to the new memory, and then all the elements in the old memory is destroyed (using a destructor). While much safer than the Realloc Strategy, it can be a bit slower. MOVE STRATEGY: This is a strategy that is also used by the STL, assuming C++11. New memory is allocated, and each element of the vector is moved (using a move constructor) to the new memory, and then all the elements in the old memory is destroyed (using a destructor). This strategy is only viable if the underlying type has a "nothrow" move constructor. Typically, it will be significantly faster than the Copy and Destroy Strategy. REALLOC STRATEGY: This strategy simply calls the realloc function, which may result in objects being copied bit-wise from one location in memory to another. For most types of objects, even those with non-trivial constructors and destructors, this is perfectly safe, as most objects really don't care what address they are stored at. As an example of where this doesn't work, STL string implementations using a "short string" optimization may consist of an object containing a pointer to a sub-object, which would be invalidated if the object were bit-wise moved from one location to another. This strategy is the fastest of them all. CHOOSING A STRATEGY: In the implementation of Vec, NTL will opt for the Realloc Strategy if one of the two conditions hold: (i) T has a trivial copy constructor and a trivial destructor, or (iii) T is a class that has been explicit declared "relocatable". (See below for details on how to declare that a class is relocatable.) Otherwise, NTL will use the Move Strategy if T has a nothrow move costructor. Otherwise, NTL will use the Copy Strategy if T has a copy constructor that is accessible (i.e., not private and not deleted). Otherwise, no reallocation implementation is provided, and a runtime error will be raised if a reallocation is required (this provides maximum flexiblilty and also maximum backward compatibility with previous versions of NTL, even though sometimes a compile-time diagnostic would be preferable). DECLARING A CLASS RELOCATABLE: One can declare T to be relocatable by adding the following line of code immediately after the definition of class T: NTL_DECLARE_RELOCATABLE((T*)) Notice the double parentheses and the "*" --- these are unfortunately necessary. This macro expands as constexpr bool DeclareRelocatableType(T*) { return true; } Inside the class Vec, this function is invoked with ((T*) 0) as the argument. By declaring relocatability via a function definition in this way, the Vec class will always find (via "Koenig lookup", or ADL) the declaration for T in the namespace in which T is defined (assuming you put the relocatability declaration there as well). You can also declare a template class to be relocatable, as in: template NTL_DECLARE_RELOCATABLE((T*)) There is also a macro NTL_DECLARE_RELOCATABLE_WHEN, which leaves off the function body, if you want something other than { return true; } NTL also defines template functions: template constexpr bool DeclareRelocatableType(T*) { return ... ; } where "..." is an expression that returns true if T is a simple type that is safe to relocate, as determined by C++11 type traits. Such simple types include scalar types and simple classes with trivial copy constructor and destructor. NTL already declares as relocatable most if the fundamental types fot which it makes sense to do so. UNSAFE VECTOR MODE: The above describes the default behavior of NTL as of version 11.0. Prior to version 11.0, the default behavior was to only use the Realloc Strategy, which is potentially unsafe. You can revert to this old behavior by configuring NTL_SAFE_VECTORS=off. ------------------------- COMPARISON TO STL VECTORS ------------------------- When the length of an NTL vector is reduced, no objects are destroyed. In contrast, when the length of an STL vector is reduced, objects are destroyed (effectively, maintaining the invariant len == init). Also, STL vectors never use anything like the Realloc Strategy. ---------------------- HISTORICAL PERSPECTIVE ---------------------- When I first started working on NTL around 1990, C++ was a much simpler language. Among other things, there were no templates and no STL, so the Vec class started out (and remained, for many years) a set of macros (indeed, this approach was advocated in the first edition of Stroustrup's book). My thinking at that time was very much "C oriented". The idea of resizing a vector without using realloc never occured to me, and all of the classes I wanted to put in vectors were relocatable. Why would you ever bother making copies of vector elements and destroy the originals when you could just realloc? It wasn't until many years later that I even realized this was somehow questionable practice. Indeed, resizing via malloc is technically undefined behavior, but it's been working for me for over 25 years without problems. Furthermore, because of the poor performance of malloc in those days (which is much better now), I designed the Vec class (and a few others) to allocate the underlying ZZ's in blocks. This not only reduces the number of calls to malloc, but it also gives better locality of reference. Experiments in the last couple of years show that this is still benefit to doing this. With all of these design decisions baked into NTL's Vec class, transitioning to STL vectors would be problematic, and is unlikely to ever happen. But as things have evolved, NTL Vec's offers many of the same convenience and safety features as STL vector's. \**************************************************************************/ // EXCEPTIONS: all functions below do not throw any exceptions, // except as noted template class Vec { public: Vec(); // initially length 0 Vec(const Vec& a); // copy constructor; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. // EXCEPTIONS: may throw Vec& operator=(const Vec& a); // assignment; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. // EXCEPTIONS: weak ES (but if it throws, neither length nor MaxLength // will change, although some previously initialized elements // may have been assigned new values). Vec(Vec&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set // will revert to copy constructor if a is fixed Vec& operator=(Vec&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set // will revert to copy assignment if *this or a is fixed // NOTE: If neither source nor destination are fixed, these operations will // be fast pointer moves and no exceptions will be thrown. If either are // fixed (say, the row in a Mat), these operations revert to copy // operations, which may either throw an exception (if NTL_EXCEPTIONS is on) // or abort the program (if NTL_EXCEPTIONS is off). // NOTE: In a vector copy assignment x=a, all iterators, references, // and pointers related to x may be invalidated by the assignment. // In a vector move assignment, the same applies to a as well. // BACKWARD COMPATIBILITY: after introducing of "move constructors" in NTL // 10.4, there have been some reports of incompatibilties. Some legacy NTL // clients have been known to assume that x=a does not invalidate pointers // into x, provided x.length() >= a.length() before the assignment. This // assumption is not valid, however, for a move assignment. Because of this // problem, as of NTL 11.0, move assignments have been disabled by default // (this is controlled by the configuration flag NTL_DISABLE_MOVE_ASSIGN). // This affects vectors and matrices, as well as many other types (such as // polynomials) that are implemented in terms of vectors. Move assignment // is not disabled. ~Vec(); // destructor: calls T's destructor for all initialized // elements in the vector, and then frees the vector itself void SetLength(long n); // set current length to n, growing vector if necessary // new objects are initialized using the default contructor for T // EXCEPTIONS: strong ES (but the vector may have been // reallocated) void SetLength(long n, const T& a); // set current length to n, growing vector if necessary // new objects are initialized using the copy contructor for T // EXCEPTIONS: strong ES (but the vector may have been // reallocated) template void SetLengthAndApply(long n, F f); // set current length to n, growing vector if necessary // any new objects are initialized using defauly constructor // for T, and after that, f is applied to each new object x // as f(x). // EXCEPTIONS: strong ES (but the vector may have been // reallocated) long length() const; // current length T& operator[](long i); const T& operator[](long i) const; // indexing operation, starting from 0. // The first version is applied to non-const Vec, // and returns a non-const reference to a T, while the second version // is applied to a const Vec and returns a const reference to a T. // EXCEPTIONS: may throw if range checking turned on, strong ES T& operator()(long i); const T& operator()(long i) const; // indexing operation, starting from 1 // The first version is applied to non-const Vec, // and returns a non-const reference to a T, while the second version // is applied to a const Vec and returns a const reference to a T. // EXCEPTIONS: may throw if range checking turned on, strong ES T* elts(); const T* elts() const; // returns address of first vector element (or 0 if no space has been // allocated for this vector). If a vector potentially has length 0, it is // safer to write v.elts() instead of &v[0]: the latter is not well defined // by the C++ standard (although this is likely an academic concern). // // The first version is applied to non-const Vec, and returns a non-const // pointer to a T, while the second version is applied to a const Vec and // returns a const reference to a T. void swap(Vec& y); // swap with y (fast: just swaps pointers) // EXCEPTIONS: throws if vectors are fixed and lengths do not match, strong ES void move(Vec& y); // move y into *this, killing y (fast: just moves pointers) // EXCEPTIONS: strong ES, raises an error if // &y != this and either y or *this are fixed void append(const T& a); // append a to end of vector; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. // EXCEPTIONS: strong ES if initializing a new element (and in any // case, if an exception throws, length and MaxLength remain // unchanged). void append(const Vec& w); // append w to end of vector; uses the assignment operator of T // for copying into locations that have already been initialized, // and uses the copy constructor for T for initializing new locations. // EXCEPTIONS: strong ES if initializing new elements (and in any // case, if an exception throws, length and MaxLength remain // unchanged). // Alternative access interface const T& get(long i) const; // v.get(i) returns v[i] void put(long i, const T& a); // v.put(i, a) equivalent to v[i] = q // Some STL compatibility typedef T value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type *iterator; typedef const value_type *const_iterator; T* data(); const T* data() const; // v.data() same as v.elts() T* begin(); const T* begin() const; // v.begin() same as v.elts() T* end(); const T* end() const; // pointer to (one past) last element (or NULL) T& at(long i); const T& at(long i) const; // indexing with range checking // the remaining member functions are a bit esoteric (skip on first // reading) Vec(INIT_SIZE_TYPE, long n); // Vec(INIT_SIZE, n) initializes vector with an intial length of n. // new objects are initialized using the default contructor for T // EXCEPTIONS: may throw Vec(INIT_SIZE_TYPE, long n, const T& a); // Vec(INIT_SIZE, n, a) initializes vector with an intial length of n. // new objects are initialized using the copy contructor for T // EXCEPTIONS: may throw void kill(); // release space and set to length 0 void SetMaxLength(long n); // allocates space and initializes up to n elements. Does not change // current length // EXCEPTIONS: may throw, strong ES void FixLength(long n); // sets length to n and prohibits all future length changes. // FixLength may only be invoked immediately after the default // construction or kill. // The kill operation is also subsequently prohibited, and swap is // allowed on fixed length vectors of the same length. // FixLength is provided mainly to implement Mat, to enforce // the restriction that all rows have the same length. // EXCEPTIONS: may throw, strong ES void FixAtCurrentLength(); // fixes the length at the cuurent length and prohibits // all future length changes. // It is required that length() == MaxLength() when called. // EXCEPTIONS: if length() != MaxLength() and error is raised; // if length() == 0, a memory allocation error may be raised. // Strong ES. long fixed() const; // test if length has been fixed by FixLength() or FixAtCurrentLength() long MaxLength() const; // maximum length, i.e., number of allocated and initialized elements long allocated() const; // the number of objects for which space has been allocated, but not // necessarily initialized; this may be larger than MaxLength(). T& RawGet(long i); const T& RawGet(long i) const; // indexing with no range checking long position(const T& a) const; // returns position of a in the vector, or -1 if it is not there. // The search is conducted from position 0 to allocated()-1 the vector, // and an error is raised if the object is found at position MaxLength() // or higher (in which case a references an uninitialized object). // Note that if NTL_CLEAN_PTR flag is set, this routine takes // linear time, and otherwise, it takes constant time. // EXCEPTIONS: may throw (as indicated above) long position1(const T& a) const; // returns position of a in the vector, or -1 if it is not there. // The search is conducted from position 0 to length()-1 of the vector. // Note that if NTL_CLEAN_PTR flag is set, this routine takes // linear time, and otherwise, it takes constant time. }; /**************************************************************************\ Some utility routines \**************************************************************************/ template void swap(Vec& x, Vec& y); // swaps x & y; same as x.swap(y) // EXCEPTIONS: same as for swap member function template void append(Vec& v, const T& a); // appends a to the end of v; same as v.append(a) // EXCEPTIONS: same as for append member function template void append(Vec& v, const Vec& w); // appends w to the end of v; same as v.append(w) // EXCEPTIONS: same as for append member function /**************************************************************************\ Input/Output The I/O format for a vector v with n elements is: [v[0] v[1] ... v[n-1]] Uses corresponding I/O operators for T \**************************************************************************/ template istream& operator>>(istream&, Vec&); // EXCEPTIONS: may throw, weak ES template ostream& operator<<(ostream&, const Vec&); // EXCEPTIONS: may throw, weak ES /**************************************************************************\ Equality Testing \**************************************************************************/ template long operator==(const Vec& a, const Vec& b); template long operator!=(const Vec& a, const Vec& b); /**************************************************************************\ Customized Constructors and Destructors Esoteric: skip on first reading...also these interfaces are subject to change When new elements in a vector need to be constructed, one of the following routines is called: void BlockConstruct(T* p, long n); // invokes T() to initialize p[i] for i = 0..n-1 void BlockConstructFromVec(T* p, long n, const T* q); // invokes T(q[i]) to initialize p[i] for i = 0..n-1; // q points to elements from a Vec void BlockConstructFromObj(T* p, long n, const T& q); // invokes T(q) to initialize p[i] for i = 0..n-1 When a vector is destroyed, the following routine is called: void BlockDestroy(T* p, long n); // invokes ~T() on p[i] for i = 0..n-1 The default behavior of these routines may be modified by overloading these functions with a custom implementation. EXCEPTIONS: In order to provide exception safe code, the Construct routines should provide strong ES; in particular, if any constructor throws, all newly constructed objects should be destroyed. Moreover, the BlockDestroy routine should not throw at all. In NTL, these routines are overridden for the ZZ_p and GF2E classes, so that many vector entries will be packed into contiguous storage locations. This reduces the number of invocations of malloc, and increases locality of reference. \**************************************************************************/ ntl-11.5.1/doc/quad_float.txt0000644417616742025610000003340014064716023017603 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: quad_float SUMMARY: The class quad_float is used to represent quadruple precision numbers. Thus, with standard IEEE floating point, you should get the equivalent of about 106 bits of precision (but actually just a bit less). The interface allows you to treat quad_floats more or less as if they were "ordinary" floating point types. See below for more implementation details. \**************************************************************************/ #include class quad_float { public: quad_float(); // = 0 quad_float(const quad_float& a); // copy constructor explicit quad_float(double a); // promotion constructor quad_float& operator=(const quad_float& a); // assignment operator quad_float& operator=(double a); ~quad_float(); static void SetOutputPrecision(long p); // This sets the number of decimal digits to be output. Default is // 10. static long OutputPrecision(); // returns current output precision. }; /**************************************************************************\ Arithmetic Operations \**************************************************************************/ quad_float operator +(const quad_float& x, const quad_float& y); quad_float operator -(const quad_float& x, const quad_float& y); quad_float operator *(const quad_float& x, const quad_float& y); quad_float operator /(const quad_float& x, const quad_float& y); // PROMOTIONS: operators +, -, *, / promote double to quad_float // on (x, y). quad_float operator -(const quad_float& x); quad_float& operator += (quad_float& x, const quad_float& y); quad_float& operator += (quad_float& x, double y); quad_float& operator -= (quad_float& x, const quad_float& y); quad_float& operator -= (quad_float& x, double y); quad_float& operator *= (quad_float& x, const quad_float& y); quad_float& operator *= (quad_float& x, double y); quad_float& operator /= (quad_float& x, const quad_float& y); quad_float& operator /= (quad_float& x, double y); quad_float& operator++(quad_float& a); // prefix void operator++(quad_float& a, int); // postfix quad_float& operator--(quad_float& a); // prefix void operator--(quad_float& a, int); // postfix /**************************************************************************\ Comparison \**************************************************************************/ long operator> (const quad_float& x, const quad_float& y); long operator>=(const quad_float& x, const quad_float& y); long operator< (const quad_float& x, const quad_float& y); long operator<=(const quad_float& x, const quad_float& y); long operator==(const quad_float& x, const quad_float& y); long operator!=(const quad_float& x, const quad_float& y); long sign(const quad_float& x); // sign of x, -1, 0, +1 long compare(const quad_float& x, const quad_float& y); // sign of x - y // PROMOTIONS: operators >, ..., != and function compare // promote double to quad_float on (x, y). /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine quad_float::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to quad_float::OutputPrecision(). \**************************************************************************/ istream& operator >> (istream& s, quad_float& x); ostream& operator << (ostream& s, const quad_float& x); /**************************************************************************\ Miscellaneous \**************************************************************************/ quad_float sqrt(const quad_float& x); quad_float floor(const quad_float& x); quad_float ceil(const quad_float& x); quad_float trunc(const quad_float& x); quad_float fabs(const quad_float& x); quad_float exp(const quad_float& x); quad_float log(const quad_float& x); void power(quad_float& x, const quad_float& a, long e); // x = a^e quad_float power(const quad_float& a, long e); void power2(quad_float& x, long e); // x = 2^e quad_float power2_quad_float(long e); quad_float ldexp(const quad_float& x, long e); // return x*2^e long IsFinite(quad_float *x); // checks if x is "finite" // pointer is used for compatability with // IsFinite(double*) void random(quad_float& x); quad_float random_quad_float(); // generate a random quad_float x with 0 <= x <= 1 /***********************************************************************\ IMPLEMENTATION DETAILS A quad_float x is represented as a pair of doubles, x.hi and x.lo, such that the number represented by x is x.hi + x.lo, where |x.lo| <= 0.5*ulp(x.hi), (*) and ulp(y) means "unit in the last place of y". For the software to work correctly, IEEE Standard Arithmetic is sufficient. However, there are a couple subtle points (see below). This is a rather weird representation; although it gives one essentially twice the precision of an ordinary double, it is not really the equivalent of quadratic precision (despite the name). For example, the number 1 + 2^{-200} can be represented exactly as a quad_float. Also, there is no real notion of "machine precision". Note that overflow/underflow for quad_floats does not follow any particularly useful rules, even if the underlying floating point arithmetic is IEEE compliant. Generally, when an overflow/underflow occurs, the resulting value is unpredicatble, although typically when overflow occurs in computing a value x, the result is non-finite (i.e., IsFinite(&x) == 0). Note, however, that some care is taken to ensure that the ZZ to quad_float conversion routine produces a non-finite value upon overflow. THE EXTENDED PRECISION PROBLEM Some machines may compute intermediate floating point results in an extended double precision format. The only machines I know that do this are old (pre-SSE) x86 machines that rely on the x87 coprocessor instruction set, so this is mainly of historical interest these days. On these old machines, intermediate results are stored in the 80-bit x87 floating point registers. These registers have 53 or 64 bits of precision---this can be set at run-time by modifying the cpu "control word" (either in assembly or through special compiler intrinsics). If the preicsion is set to 64 bits, the quad_float routines will produce incorrect results. The best way to fix this problem is to set the precsion of the x87 registers to 53 at the beginning of program execution and to leave it. This is what Windows with MSVC++ does. On Linux with gcc (and other compilers), however, this is not the case: the precision of the registers is set to 64 bits. To fix this problem, the build process for NTL automatically checks for extended double preceision, and if detected, arranges for the quad_float routines to locally set the precision to 53 bits on entry and back to 64 bits on exit. This only works with GCC and GCC-compatible compilers (including CLANG and ICC) that support GCC's inline assembly syntax. The configuration flags NTL_FIX_X86 or NTL_NO_FIX_X86 can be set to override NTL's default behavior (but I've never really seen a need to use them). If all else fails, NTL will revert to a strategy of forcing all intermediate floating point results into memory. This is not an ideal fix, since it is not fully equivalent to 53-bit precision (because of double rounding), but it works (although to be honest, I've never seen a full proof of correctness in this case). NTL's quad_float code does this by storing intermediate results in local variables declared to be 'volatile'. This is the solution to the problem that NTL uses if it detects the problem and can't fix it using the control word hack mentioned above. In fact, I've never seen a platform where this strategy is required. To reiterate: this is all mainly of historical interest, as the x87 coprocessor is pretty much not used any more. THE FMA PROBLEM Some CPUs come equipped with a fused-multiply-add (FMA) instruction, which computes x + a*b with just a single rounding. While this generally is faster and more precise than performing this using two instructions and two roundings, FMA instructions can break the logic of quad_float. To mitigate this problem, NTL's configuration script will attempt to detect the existence of FMA's, and if detected, to supress them using a compiler flag. Right now, NTL's configuration script only attempts to fix this problem for the GCC, CLANG, and ICC compilers. GCC, this is done with the flag -ffp-contract=off (or the flag -mno-fused-madd, which is obsolete in new versions of GCC). On CLANG, this is also done with the flag -ffp-contract=off, although by default, CLANG will not emit FMA's, so this should not be necessary. On ICC, this is done by the fp_contract(off) pragma. This is accomplished by passing information through the make variable NOCONTRACT, which is only used in the compilation of quad_float.cpp. THE FLOATING POINT REASSOCIATION PROBLEM The C++ standard says that compilers must issue instructions that respect the grouping of floating point operations. So the compiler is not allowed to compile (a+b)+c as a+(b+c). Most compilers repect this rule by default, but some do not (such as Intel's ICC compiler). The logic of quad_float relies crucially on this rule. In fact, NTL attempts to ensure that all of its source files get compiled with this rule in force. To this end, if the configuration script detects an ICC compiler, it will pass the "-fp-model precise" flag through to the compiler (via the CXXAUTOFLAGS make variable) when compiling *all* source files (not just quad_float.cpp). BACKGROUND INFO The code NTL uses algorithms designed by Knuth, Kahan, Dekker, and Linnainmaa. The original transcription to C++ was done by Douglas Priest. Enhancements and bug fixes were done by Keith Briggs --- see http://keithbriggs.info/doubledouble.html. The NTL version is a stripped down version of Briggs' code, with some bug fixes and portability improvements. Here is a brief annotated bibliography (compiled by Priest) of papers dealing with DP and similar techniques, arranged chronologically. Kahan, W., Further Remarks on Reducing Truncation Errors, {\it Comm.\ ACM\/} {\bf 8} (1965), 40. M{\o}ller, O., Quasi Double Precision in Floating-Point Addition, {\it BIT\/} {\bf 5} (1965), 37--50. The two papers that first presented the idea of recovering the roundoff of a sum. Dekker, T., A Floating-Point Technique for Extending the Available Precision, {\it Numer.\ Math.} {\bf 18} (1971), 224--242. The classic reference for DP algorithms for sum, product, quotient, and square root. Pichat, M., Correction d'une Somme en Arithmetique \`a Virgule Flottante, {\it Numer.\ Math.} {\bf 19} (1972), 400--406. An iterative algorithm for computing a protracted sum to working precision by repeatedly applying the sum-and-roundoff method. Linnainmaa, S., Analysis of Some Known Methods of Improving the Accuracy of Floating-Point Sums, {\it BIT\/} {\bf 14} (1974), 167--202. Comparison of Kahan and M{\o}ller algorithms with variations given by Knuth. Bohlender, G., Floating-Point Computation of Functions with Maximum Accuracy, {\it IEEE Trans.\ Comput.} {\bf C-26} (1977), 621--632. Extended the analysis of Pichat's algorithm to compute a multi-word representation of the exact sum of n working precision numbers. This is the algorithm Kahan has called "distillation". Linnainmaa, S., Software for Doubled-Precision Floating-Point Computations, {\it ACM Trans.\ Math.\ Soft.} {\bf 7} (1981), 272--283. Generalized the hypotheses of Dekker and showed how to take advantage of extended precision where available. Leuprecht, H., and W.~Oberaigner, Parallel Algorithms for the Rounding-Exact Summation of Floating-Point Numbers, {\it Computing} {\bf 28} (1982), 89--104. Variations of distillation appropriate for parallel and vector architectures. Kahan, W., Paradoxes in Concepts of Accuracy, lecture notes from Joint Seminar on Issues and Directions in Scientific Computation, Berkeley, 1989. Gives the more accurate DP sum I've shown above, discusses some examples. Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, in P.~Kornerup and D.~Matula, Eds., {\it Proc.\ 10th Symposium on Com- puter Arithmetic}, IEEE Computer Society Press, Los Alamitos, Calif., 1991. Extends from DP to arbitrary precision; gives portable algorithms and general proofs. Sorensen, D., and P.~Tang, On the Orthogonality of Eigenvectors Computed by Divide-and-Conquer Techniques, {\it SIAM J.\ Num.\ Anal.} {\bf 28} (1991), 1752--1775. Uses some DP arithmetic to retain orthogonality of eigenvectors computed by a parallel divide-and-conquer scheme. Priest, D., On Properties of Floating Point Arithmetics: Numerical Stability and the Cost of Accurate Computations, Ph.D. dissertation, University of California at Berkeley, 1992. More examples, organizes proofs in terms of common properties of fp addition/subtraction, gives other summation algorithms. Another relevant paper: X. S. Li, et al. Design, implementation, and testing of extended and mixed precision BLAS. ACM Trans. Math. Soft., 28:152-205, 2002. \***********************************************************************/ ntl-11.5.1/doc/sedscript.txt0000644417616742025610000000536714064716023017477 0ustar gid-shoupvpug-gid-shoupv # This is a sed script to make most of the common syntactic # changes necessary to move from NTL 2.0 to 3.0. # If this file is in sedscript.txt (as it originally is) # the command # sed -f sedscript.txt < old.c > new.c # will convert old.c to new.c with the necesary changes. # # Please note that this script is niether "sound" or "complete", # but should still be useful. # rename some classes s/BB/GF2X/g s/BB_p/GF2E/g s/GF2Vector/vec_GF2/g s/GF2Matrix/mat_GF2/g # rename some functions s/ZZ_pInit(/ZZ_p::init(/g s/zz_pInit(/zz_p::init(/g s/zz_pFFTInit(/zz_p::FFTInit(/ s/GF2EInit(/GF2E::init(/g s/LowBits/trunc/g s/Long(/to_long(/g s/XDouble(/to_xdouble(/g s/Quad_float(/to_quad_float(/g s/trace(/TraceMod(/g s/norm(/NormMod(/g s/MinPoly(/MinPolyMod(/g s/IrredPoly(/IrredPolyMod(/g s/CharPoly(/CharPolyMod(/g # rename generic vector, pair, matrix macro instantations # these assume no embedded blanks s/vector_decl(\(.*\))/ntl_vector_decl(\1,vec_\1)/g s/vector_io_decl(\(.*\))/ntl_io_vector_decl(\1,vec_\1)/g s/vector_eq_decl(\(.*\))/ntl_eq_vector_decl(\1,vec_\1)/g # s/vector_impl(\(.*\))/ntl_vector_impl(\1,vec_\1)/g s/vector_impl_plain(\(.*\))/ntl_vector_impl_plain(\1,vec_\1)/g s/vector_io_impl(\(.*\))/ntl_io_vector_impl(\1,vec_\1)/g s/vector_eq_impl(\(.*\))/ntl_eq_vector_impl(\1,vec_\1)/g # s/matrix_decl(\(.*\))/ntl_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_io_decl(\(.*\))/ntl_io_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_eq_decl(\(.*\))/ntl_eq_matrix_decl(\1,vec_\1,vec_vec_\1,mat_\1)/g # s/matrix_impl(\(.*\))/ntl_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_io_impl(\(.*\))/ntl_io_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g s/matrix_eq_impl(\(.*\))/ntl_eq_matrix_impl(\1,vec_\1,vec_vec_\1,mat_\1)/g # s/pair_decl(\(.*\),\(.*\))/ntl_pair_decl(\1,\2,pair_\1_\2)/g s/pair_io_decl(\(.*\),\(.*\))/ntl_pair_io_decl(\1,\2,pair_\1_\2)/g s/pair_eq_decl(\(.*\),\(.*\))/ntl_pair_eq_decl(\1,\2,pair_\1_\2)/g # s/pair_impl(\(.*\),\(.*\))/ntl_pair_impl(\1,\2,pair_\1_\2)/g s/pair_io_impl(\(.*\),\(.*\))/ntl_pair_io_impl(\1,\2,pair_\1_\2)/g s/pair_eq_impl(\(.*\),\(.*\))/ntl_pair_eq_impl(\1,\2,pair_\1_\2)/g # rename type names for the generic types # these allow embedded blanks s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # # repeat to handle one nesting level # s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # # repeat to handle two nesting levels # s/pair *( *\([^,() ]*\) *, *\([^() ]*\) *)/pair_\1_\2/g s/vector *( *\([^() ]*\) *)/vec_\1/g s/matrix *( *\([^() ]*\) *)/mat_\1/g # rename header files for generic types s/vector\.h/ntl_vector\.h/ s/matrix\.h/ntl_matrix\.h/ s/pair\.h/ntl_pair\.h/ ntl-11.5.1/doc/tools.txt0000644417616742025610000001253414064716023016631 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: tools SUMMARY: Some useful tools that are used throughout NTL. \**************************************************************************/ #include #include #include #include #include #include #include #include #include double GetTime(); // returns number of seconds of CPU time used by this process. double GetWallTime(); // returns the "wall clock" time, measured since the beginning // of some unspecified epoch. This is useful for measuring the // performance of multi-threaded code, since in this case, // GetTime does not return very useful information in that case. void PrintTime(ostream& s, double t); // prints the time t (in seconds) to s in the format // ss or mm:ss or hh:mm:ss, // where the value t is first rounded to the nearest integer. long IsWhiteSpace(long c); // returns 1 if c is "white space" (as defined by isspace is the // standard library...usually blanks, tabs, newlines), and 0 otherwise. long SkipWhiteSpace(istream& s); // skips white space (as defined by IsWhiteSpace). // Return value is 0 if end-of-file is reached; otherwise, // return value is 1. long IsEOFChar(long c); // test if c == EOF long CharToIntVal(long c); // returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f'; // otherwise, the return value is -1. char IntValToChar(long x); // returns the hexadecimal digit '0'..'9', 'a'..'f' representing x; // an error is raised if x < 0 or x > 15. long IsFinite(double *p); // Returns 1 if *p is a "finite" floating point number. // A pointer is used to ensure that the number is in memory, // which on some architectures (notably x86/Pentium) can make a difference. // some min/max and swap routines: int min(int a, int b); int max(int a, int b); long min(long a, long b); long max(long a, long b); long min(int a, long b); long max(int a, long b); long min(long a, int b); long max(long a, int b); unsigned int min(unsigned int a, unsigned int b); unsigned int max(unsigned int a, unsigned int b); unsigned long min(unsigned long a, unsigned long b); unsigned long max(unsigned long a, unsigned long b); unsigned long min(unsigned int a, unsigned long b); unsigned long max(unsigned int a, unsigned long b); unsigned long min(unsigned long a, unsigned int b); unsigned long max(unsigned long a, unsigned int b); void swap(long& a, long& b); void swap(int& a, int& b); // defined here are all the conversion routines among the types // int, long, float, double. See conversions.txt for complete details. // The following platform-dependent macros are defined: #define NTL_BITS_PER_LONG (...) /* bits in a long */ #define NTL_MAX_LONG (...) /* max value of a long */ #define NTL_MIN_LONG (...) /* min value of a long */ #define NTL_BITS_PER_INT (...) /* bits in a int */ #define NTL_MAX_INT (...) /* max value of a int */ #define NTL_MIN_INT (...) /* min value of a int */ #define NTL_DOUBLE_PRECISION (...) /* # of bits of precision in a double */ #define NTL_FDOUBLE_PRECISION (...) /* the double value 2^{NTL_DOUBLE_PRECISION-1} */ #define NTL_ARITH_RIGHT_SHIFT (...) /* 1 if signed right-shift is arithmetic; 0 otherwise */ #define NTL_EXT_DOUBLE (...) /* 1 if platform has "extended" doubles; 0 otherwise */ // ERROR HANDLING void TerminalError(const char *s); // print an error message and call abort extern thread_local void (*ErrorMsgCallback)(const char *); extern thread_local void (*ErrorCallback)(); // Pointers (initially NULL) to callback functions. // Upon encountering an unrecoverable error with an error // message s, the following happens: // // if (ErrorMsgCallback) // (*ErrorMsgCallback)(s); // else // cerr << s << "\n"; // // if (ErrorCallback) (*ErrorCallback)(); // abort(); // // NOTE: if threads are enabled, these are actually thread_local variables. // The following classes are defined even if exceptions are not // enabled with NTL_EXCEPTIONS class ErrorObject : public runtime_error { public: ErrorObject(const char *msg); }; class LogicErrorObject : public ErrorObject { public: LogicErrorObject(const char *msg); }; class ArithmeticErrorObject : public ErrorObject { public: ArithmeticErrorObject(const char *msg); }; class ResourceErrorObject : public ErrorObject { public: ResourceErrorObject(const char *msg); }; class FileErrorObject : public ErrorObject { public: FileErrorObject(const char *msg); }; class InputErrorObject : public ErrorObject { public: InputErrorObject(const char *msg); }; // The following functions throw the indicated exception if // exceptions are enabled with NTL_EXCEPTIONS; otherwise, // they simply invoke TerminalError. void MemoryError(); // throws bad_alloc void Error(const char *msg); // throws ErrorObject void LogicError(const char *msg); // throws LogicErrorObject void ArithmeticError(const char *msg); // throws ArithmeticErrorObject void ResourceError(const char *msg); // throws ResourceErrorObject void FileError(const char *msg); // throws FileErrorObject void InputError(const char *msg); // throws InputErrorObject ntl-11.5.1/doc/vec_GF2.txt0000644417616742025610000002107314064716023016702 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_GF2 SUMMARY: The class Vec is explicitly specialized. It behaves much like a generic Vec (see vector.txt), but there are some differences. For efficiency, elements of a Vec are "packed" into a word. You can still use subscript notation v[i] or v(i). For const vectors, these evaluate to values of type const GF2. For non-const vectors, these evaluate to values of the special type ref_GF2, which is defined in the GF2 header file. There are implicit conversions from ref_GF2 to const GF2 and from GF2& to ref_GF2. Therefore, if you want to declare a function that takes a non-const reference to a GF2, you should declare the parameter of type ref_GF2: this will allow you to pass variables of type GF2 as well as elements of vec_GF2's obtained through indexing. As an alternative, one can use the get and put methods below to access vector elements. There is a subtle but important difference in the semantics of Vec and that of generic NTL vectors. With a Vec, whenever its length is increased (via SetLength), the "new" bits are always 0. For example, if v.length() == 20, then v.SetLength(10); v.setLength(20); will effectively clear bits 10..19 of v. This is quite different from the semantics of generic NTL vectors, where the above sequence would not change the value of v at all. One has to be aware of this difference, but it will not matter in most ordinary circumstances. Another thing to be aware of is the use of Vec in range-based for loops. The safest ways to do this are as follows: for (auto&& item : vec) { ... } // for read-only or read/write access or for (GF2 item : vec) { ... } // for access via a copy Note that: * declaring item as "auto&" or "GF2&" will yield a syntax error * declaring item as "auto" or "const auto&" will potentially allow code to modify vec via item, without a warning or error, contrary to expectations (although this cannot happen if vec itself is const) However, declaring item as "auto&&" will work as expected, and the compiler will raise an error if you try to modify a const Vec. All of these issues arise because ref_GF2 is not a true reference, and the semantics of "auto" and "auto&" interact badly. Similar issues arise with vector in the STL. \**************************************************************************/ template<> class Vec { public: Vec(); // 0 length vector Vec(INIT_SIZE_TYPE, long n); // initialize to length n // usage: Vec(INIT_SIZE, n) Vec(const Vec& a); // copy constructor Vec& operator=(const Vec& a); // assignment Vec(Vec&& a); // move constructor (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set // will revert to copy constructor if a is fixed #ifndef NTL_DISABLE_MOVE_ASSIGN Vec& operator=(Vec&& a); // move assignment (C++11 only) // declared noexcept unless NTL_EXCEPTIONS flag is set // will revert to copy assignment if *this or a is fixed #endif ~Vec(); // destructor void SetLength(long n); // set length to n bits void SetLength(long n, GF2 a); // set length to n, if length increases, initialize new bits to a void SetMaxLength(long n); // allocate space for n bits long length() const; // current length, in bits long MaxLength() const; // maximum length, i.e., the maximum // value passed to either SetLength or SetMaxLength // since creation or last kill long allocated() const; // number of bits for which space is allocated; // if n <= v.allocated(), then v.SetLength(n) // will not result in any memory re-allocation. // INVARIANT: // length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4) void FixLength(long n); // fix length to n bits // can only be applied after default initialization or kill void FixAtCurrentLength(); // fixes the length at the cuurent length and prohibits // all future length changes. // It is required that length() == MaxLength() when called. // EXCEPTIONS: if length() != MaxLength() and error is raised; // Strong ES. long fixed() const; // test if length has been fixed void kill(); // free space and make length 0 const GF2 get(long i) const; // fetch value at index i (indexing from 0) void put(long i, GF2 a); // write value a to index i (indexing from 0) void put(long i, long a); // Here are the subscripting operators, defined using the // "helper" class ref_GF2 ref_GF2 operator[](long i); ref_GF2 operator()(long i); const GF2 operator[](long i) const; const GF2 operator()(long i) const; void swap(Vec& y); // swap with y (fast: just swaps pointers) void move(Vec& y); // move y to *this (fast: just moves pointers) void append(GF2 a); // append a to end of vector void append(const Vec& w); // append w to end of vector // Some partial STL compatibility...also used // to interface with the Matrix template class typedef GF2 value_type; typedef ref_GF2 reference; typedef const GF2 const_reference; typedef /* implementation defined type */ iterator; typedef /* implementation defined type */ const_iterator; ref_GF2 at(long i); const GF2 at(long i) const; // indexing with range checking iterator begin(); const_iterator begin() const; // pointer to beginning of vector iterator end(); const_iterator end() const; // pointer to (one past) end of vector // NOTES: The iterator types act like pointers. You can perform all the // usual arithmetic on them, as well as dereferencing and subscripting. // Dereferencing an iterator yields a ref_GF2. Dereferencing a // const_iterator yields a const GF2. }; void swap(Vec& x, Vec& y); // swap x and y (fast pointer swap) void append(Vec& v, GF2 a); // append a to v void append(Vec& v, const Vec& a); // append a to v // equality operators: long operator==(const Vec& a, const Vec& b); long operator!=(const Vec& a, const Vec& b); // I/O operators: ostream& operator<<(ostream& s, const Vec& a); istream& operator>>(istream& s, Vec& a); // The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1". // On input, the a_i may be arbitrary integers, which are reduced mod 2. typedef Vec vec_GF2; // backward compatibility // utility routines: void clear(vec_GF2& x); // clear all bits--length unchanged long IsZero(const vec_GF2& a); // test if all bits are zero void shift(vec_GF2& x, const vec_GF2& a, long n); vec_GF2 shift(const vec_GF2& a, long n); // x = a shifted n places, where n may be positive or negative. // Generally, x[i] = a[i-n], so positive n shifts to a higher index. // The length of x is set to the length of a, and bits // are zero-filled or discarded as necessary. void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed vec_GF2 reverse(const vec_GF2& a); long weight(const vec_GF2& a); // return number of 1 bits in a // arithmetic operations over GF(2): void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b); void negate(vec_GF2& x, const vec_GF2& a); void mul(vec_GF2& x, const vec_GF2& a, GF2 b); void mul(vec_GF2& x, const vec_GF2& a, long b); void mul(vec_GF2& x, GF2 a, const vec_GF2& b); void mul(vec_GF2& x, long a, const vec_GF2& b); // x = a * b void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b); // vectors may differ in length void VectorCopy(vec_GF2& x, const vec_GF2& a, long n); vec_GF2 VectorCopy(const vec_GF2& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_GF2& x, long n); // x = random vector of length n vec_GF2 random_vec_GF2(long n); // arithmetic operator notation: vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b); vec_GF2 operator-(const vec_GF2& a); // scalar mul: vec_GF2 operator*(const vec_GF2& a, GF2 b); vec_GF2 operator*(const vec_GF2& a, long b); vec_GF2 operator*(GF2 a, const vec_GF2& b); vec_GF2 operator*(long a, const vec_GF2& b); // inner product: inline GF2 operator*(const vec_GF2& a, const vec_GF2& b); // assignment operator notation: vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a); vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a); vec_GF2& operator*=(vec_GF2& x, GF2 a); vec_GF2& operator*=(vec_GF2& x, long a); ntl-11.5.1/doc/vec_GF2E.txt0000644417616742025610000000565614064716023017020 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_GF2E SUMMARY: Provides vectors over GF2E, along with some related operations. \**************************************************************************/ #include #include typedef Vec vec_GF2E; // backward compatibility void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b); void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b); void mul(vec_GF2E& x, const vec_GF2E& a, long b); void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b); void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b); void mul(vec_GF2E& x, long a, const vec_GF2E& b); // x = a * b void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = a + b void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = a - b = x + a void negate(vec_GF2E& x, const vec_GF2E& a); // x = - a = a void clear(vec_GF2E& x); // x = 0 (length unchanged) long IsZero(const vec_GF2E& a); // test if a is the zero vector void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), b.length()) void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n); vec_GF2E VectorCopy(const vec_GF2E& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_GF2E& x, long n); // x = random vector of length n vec_GF2E random_vec_GF2E(long n); // operator notation: vec_GF2E operator+(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a, const vec_GF2E& b); vec_GF2E operator-(const vec_GF2E& a); // vector/scalar multiplication: vec_GF2E operator*(const vec_GF2E& a, const GF2E& b); vec_GF2E operator*(const vec_GF2E& a, GF2 b); vec_GF2E operator*(const vec_GF2E& a, long b); vec_GF2E operator*(const GF2E& a, const vec_GF2E& b); vec_GF2E operator*(GF2 a, const vec_GF2E& b); vec_GF2E operator*(long a, const vec_GF2E& b); // inner product: GF2E operator*(const vec_GF2E& a, const vec_GF2E& b); // assignment operator notation: vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a); vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a); vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a); vec_GF2E& operator*=(vec_GF2E& x, GF2 a); vec_GF2E& operator*=(vec_GF2E& x, long a); // Implementation note: the BlockConstruct routine has been customized // for GF2E so that when a vec_GF2E is grown, space for the needed // elements is allocated in one contiguous chunk. This saves on calls to // malloc and free, and should also yield better locality of reference. // One consequence of this is that swapping an element of a vec_GF2E // with another GF2E can not be implemented by pointer swap, and will in // this case be done by copy. ntl-11.5.1/doc/vec_RR.txt0000644417616742025610000000340714064716023016650 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_RR SUMMARY: Defines the class vec_RR. \**************************************************************************/ typedef Vec vec_RR; // backward compatibility void mul(vec_RR& x, const vec_RR& a, const RR& b); void mul(vec_RR& x, const vec_RR& a, double b); void mul(vec_RR& x, const RR& a, const vec_RR& b); void mul(vec_RR& x, double a, const vec_RR& b); // x = a * b void add(vec_RR& x, const vec_RR& a, const vec_RR& b); // x = a + b void sub(vec_RR& x, const vec_RR& a, const vec_RR& b); // x = a - b void clear(vec_RR& x); // x = 0 (length unchanged) void negate(vec_RR& x, const vec_RR& a); // x = -a long IsZero(const vec_RR& a); // test if a is the zero vector void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b); // x = inner product of a and b, padded with zeros to make the lengths // even. void VectorCopy(vec_RR& x, const vec_RR& a, long n); vec_RR VectorCopy(const vec_RR& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_RR operator+(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a, const vec_RR& b); vec_RR operator-(const vec_RR& a); // vector/scalar multiplication: vec_RR operator*(const vec_RR& a, const RR& b); vec_RR operator*(const vec_RR& a, double b); vec_RR operator*(const RR& a, const vec_RR& b); vec_RR operator*(double a, const vec_RR& b); // inner product: RR operator*(const vec_RR& a, const vec_RR& b); // assignment operator notation: vec_RR& operator+=(vec_RR& x, const vec_RR& a); vec_RR& operator-=(vec_RR& x, const vec_RR& a); vec_RR& operator*=(vec_RR& x, const RR& a); vec_RR& operator*=(vec_RR& x, double a); ntl-11.5.1/doc/vec_ZZ.txt0000644417616742025610000000337414064716023016673 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_ZZ SUMMARY: Defines the class vec_ZZ. \**************************************************************************/ typedef Vec vec_ZZ; // backward compatibility void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b); void mul(vec_ZZ& x, const vec_ZZ& a, long b); void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b); void mul(vec_ZZ& x, long a, const vec_ZZ& b); // x = a * b void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = a + b void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = a - b void clear(vec_ZZ& x); // x = 0 (length unchanged) void negate(vec_ZZ& x, const vec_ZZ& a); // x = -a long IsZero(const vec_ZZ& a); // test if a is the zero vector void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b); // x = inner product of a and b, padded with zeros to make the lengths // even. void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n); vec_ZZ VectorCopy(const vec_ZZ& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. // operator notation: vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b); vec_ZZ operator-(const vec_ZZ& a); // vector/scalar multiplication: vec_ZZ operator*(const vec_ZZ& a, const ZZ& b); vec_ZZ operator*(const vec_ZZ& a, long b); vec_ZZ operator*(const ZZ& a, const vec_ZZ& b); vec_ZZ operator*(long a, const vec_ZZ& b); // inner product: ZZ operator*(const vec_ZZ& a, const vec_ZZ& b); // assignment operator notation: vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a); vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a); vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a); vec_ZZ& operator*=(vec_ZZ& x, long a); ntl-11.5.1/doc/vec_ZZ_p.txt0000644417616742025610000000532314064716023017206 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_ZZ_p SUMMARY: Provides vectors over ZZ_p, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_ZZ_p; // backward compatibility void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b); void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b); void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b); void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b); // x = a * b void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = a + b void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = a - b void clear(vec_ZZ_p& x); // x = 0 (length unchanged) void negate(vec_ZZ_p& x, const vec_ZZ_p& a); // x = -a long IsZero(const vec_ZZ_p& a); // test if a is the zero vector void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n); vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_ZZ_p& x, long n); // x = random vector of length n vec_ZZ_p random_vec_ZZ_p(long n); // operator notation: vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator-(const vec_ZZ_p& a); // vector/scalar multiplication: vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b); vec_ZZ_p operator*(const vec_ZZ_p& a, long b); vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b); vec_ZZ_p operator*(long a, const vec_ZZ_p& b); // inner product: ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b); // assignment operator notation: vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a); vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a); vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a); vec_ZZ_p& operator*=(vec_ZZ_p& x, long a); // Implementation note: the BlockConstruct routine has been customized // for ZZ_p so that when a vec_ZZ_p is grown, space for the needed // elements is allocated in one contiguous chunk. This saves on calls to // malloc and free, and should also yield better locality of reference. // One connsequence of this is that swapping an element of a vec_ZZ_p // with another ZZ_p can not be implemented by pointer swap, and will in // this case be done by copy. ntl-11.5.1/doc/vec_ZZ_pE.txt0000644417616742025610000000514614064716023017316 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_ZZ_pE SUMMARY: Provides vectors over ZZ_pE, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_ZZ_pE; // backward compatibility void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b); void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b); void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b); void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b); // x = a * b void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = a + b void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = a - b void clear(vec_ZZ_pE& x); // x = 0 (length unchanged) void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a); // x = -a long IsZero(const vec_ZZ_pE& a); // test if a is the zero vector void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n); vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_ZZ_pE& x, long n); // x = random vector of length n vec_ZZ_pE random_vec_ZZ_pE(long n); // operator notation: vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator-(const vec_ZZ_pE& a); // vector/scalar multiplication: vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b); vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b); vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b); vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b); // inner product: ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b); // assignment operator notation: vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a); vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a); vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a); ntl-11.5.1/doc/vec_lzz_p.txt0000644417616742025610000000504614064716023017464 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_zz_p SUMMARY: Provides vectors over zz_p, along with some related operations. \**************************************************************************/ #include "zz_p.h" #include "vec_zz.h" #include typedef Vec vec_zz_p; // backward compatibility void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b); void mul(vec_zz_p& x, const vec_zz_p& a, long b); void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b); void mul(vec_zz_p& x, long a, const vec_zz_p& b); // x = a * b void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = a + b void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = a - b void clear(vec_zz_p& x); // x = 0 (length unchanged) void negate(vec_zz_p& x, const vec_zz_p& a); // x = -a long IsZero(const vec_zz_p& a); // test if a is the zero vector void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n); vec_zz_p VectorCopy(const vec_zz_p& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_zz_p& x, long n); // x = random vector of length n vec_zz_p random_vec_zz_p(long n); void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) long CRT(vec_ZZ& a, ZZ& prod, const vec_zz_p& A); // Incremental Chinese Remaindering: If p is the current zz_p modulus with // (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p, // with coefficients in the interval (-p*prod/2, p*prod/2]; // Sets a := a', prod := p*prod, and returns 1 if a's value changed. // operator notation: vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b); vec_zz_p operator-(const vec_zz_p& a); // vector/scalar multiplication: vec_zz_p operator*(const vec_zz_p& a, zz_p b); vec_zz_p operator*(const vec_zz_p& a, long b); vec_zz_p operator*(zz_p a, const vec_zz_p& b); vec_zz_p operator*(long a, const vec_zz_p& b); // inner product: zz_p operator*(const vec_zz_p& a, const vec_zz_p& b); // assignment operator notation: vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a); vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a); vec_zz_p& operator*=(vec_zz_p& x, zz_p a); vec_zz_p& operator*=(vec_zz_p& x, long a); ntl-11.5.1/doc/vec_lzz_pE.txt0000644417616742025610000000515014064716023017565 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: vec_zz_pE SUMMARY: Provides vectors over zz_pE, along with some related operations. \**************************************************************************/ #include #include #include typedef Vec vec_zz_pE; // backward compatibility void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b); void mul(vec_zz_pE& x, const vec_zz_pE& a, long b); void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b); void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b); void mul(vec_zz_pE& x, long a, const vec_zz_pE& b); // x = a * b void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = a + b void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = a - b void clear(vec_zz_pE& x); // x = 0 (length unchanged) void negate(vec_zz_pE& x, const vec_zz_pE& a); // x = -a long IsZero(const vec_zz_pE& a); // test if a is the zero vector void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b); // x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), // b.length()) void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b, long offset); // x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(), // b.length()+offset) void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n); vec_zz_pE VectorCopy(const vec_zz_pE& a, long n); // x = a copy of a of length exactly n. // The input is truncated or padded with zeroes, as necessary. void random(vec_zz_pE& x, long n); // x = random vector of length n vec_zz_pE random_vec_zz_pE(long n); // operator notation: vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator-(const vec_zz_pE& a); // vector/scalar multiplication: vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b); vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b); vec_zz_pE operator*(const vec_zz_pE& a, long b); vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b); vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b); vec_zz_pE operator*(long a, const vec_zz_pE& b); // inner product: zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b); // assignment operator notation: vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a); vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a); vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a); vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a); vec_zz_pE& operator*=(vec_zz_pE& x, long a); ntl-11.5.1/doc/xdouble.txt0000644417616742025610000001374114064716023017134 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: xdouble SUMMARY: The class xdouble is used to represent floating point numbers with the same precision as a 'double', but with extended exponent range (offering a few more bits than that of a 'long' for the exponent). The programming interface for xdoubles is almost identical to that of ordinary doubles. \**************************************************************************/ #include class xdouble { public: xdouble(); // = 0 xdouble(const xdouble& a); // copy constructor explicit xdouble(double a); // promotion constructor xdouble& operator=(const xdouble& a); // assignment operator xdouble& operator=(double a); ~xdouble(); double mantissa() const; // read-only access to mantissa long exponent() const; // read-only access to exponenent static void SetOutputPrecision(long p); // This sets the number of decimal digits to be output. Default is // 10. static long OutputPrecision(); // returns current output precision. }; /**************************************************************************\ Arithmetic Operations The following are the standard arithmetic operators, whose meaning should be clear. \**************************************************************************/ xdouble operator+(const xdouble& a, const xdouble& b); xdouble operator-(const xdouble& a, const xdouble& b); xdouble operator*(const xdouble& a, const xdouble& b); xdouble operator/(const xdouble& a, const xdouble& b); // PROMOTIONS: +, -, *, / promote double to xdouble on (a, b). xdouble operator-(const xdouble& a); xdouble& operator+=(xdouble& a, const xdouble& b); xdouble& operator+=(xdouble& a, double b); xdouble& operator-=(xdouble& a, const xdouble& b); xdouble& operator-=(xdouble& a, double b); xdouble& operator*=(xdouble& a, const xdouble& b); xdouble& operator*=(xdouble& a, double b); xdouble& operator/=(xdouble& a, const xdouble& b); xdouble& operator/=(xdouble& a, xdouble b); xdouble& operator++(xdouble& a); // prefix void operator++(xdouble& a, int); // postfix xdouble& operator--(xdouble& a); // prefix void operator--(xdouble& a, int); // postfix /**************************************************************************\ Comparison \**************************************************************************/ long sign(const xdouble& a); // returns sign (+1, -1, 0) of a long compare(const xdouble& a, const xdouble& b); // returns sign of a - b long operator==(const xdouble& a, const xdouble& b); long operator!=(const xdouble& a, const xdouble& b); long operator<=(const xdouble& a, const xdouble& b); long operator>=(const xdouble& a, const xdouble& b); long operator <(const xdouble& a, const xdouble& b); long operator >(const xdouble& a, const xdouble& b); // PROMOTIONS: compare and operators ==, ..., > promote double to xdouble // on (a, b). /**************************************************************************\ Input/Output Input Syntax: : [ "-" ] : [ ] | : | "." | "." | "." : | : "0" | ... | "9" : ( "E" | "e" ) [ "+" | "-" ] Examples of valid input: 17 1.5 0.5 .5 5. -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10 Note that the number of decimal digits of precision that are used for output can be set to any number p >= 1 by calling the routine xdouble::SetOutputPrecision(p). The default value of p is 10. The current value of p is returned by a call to xdouble::OutputPrecision(). \**************************************************************************/ ostream& operator<<(ostream& s, const xdouble& a); istream& operator>>(istream& s, xdouble& x); /**************************************************************************\ Miscellaneous \**************************************************************************/ xdouble trunc(const xdouble& a); // returns integer obtained by truncating xdouble floor(const xdouble& a); // returns greatest integer <= a xdouble ceil(const xdouble& a); // returns smallest integer >= a xdouble fabs(const xdouble& a); // returns |a| xdouble sqrt(const xdouble& a); // returns a^{1/2}; error is raised if a < 0 double log(const xdouble& a); // returns log(a) (note return val is double!) xdouble xexp(double a); // returns exp(a) (note argument is double!) xdouble exp(const double& a); // equivalent to xexp(to_double(a)) void power(xdouble& z, const xdouble& a, const ZZ& e); xdouble power(const xdouble& a, const ZZ& e); void power(xdouble& z, const xdouble& a, long e); xdouble power(const xdouble& a, long e); // z = a^e, e may be negative void power2(xdouble& z, long e); xdouble power2_xdouble(long e); // z = 2^e, e may be negative void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c); // z = a + b*c, but faster void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c); xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c); // z = a - b*c, but faster /**************************************************************************\ Implementation details: An xdouble is represented as a mantissa/exponent pair (x, e), where x is a double and e is a long. The real number represented by (x, e) is x * NTL_XD_BOUND^e, where NTL_XD_BOUND = NTL_XD_HBOUND^2, and NTL_XD_HBOUND = 2^{(max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4)}. Also, the mantissa x satisfies 1/NTL_XD_HBOUND <= |x| <= NTL_XD_HBOUND, except that the number 0 is always represented as (0, 0). Both NTL_XD_BOUND and NTL_XD_HBOUND are macros defined in . SIZE INVARIANT: |e| < 2^(NTL_BITS_PER_LONG-4). \**************************************************************************/ ntl-11.5.1/doc/names.txt0000644417616742025610000000653114064716023016574 0ustar gid-shoupvpug-gid-shoupv Here is a list of the macro names that have changed. As you can see, most of these are anyway undocumented, and you probably never knew they existed. Also changed, but not listed here, are the macros used to prevent double inclusion of ".h" files. Also, the identifiers like INIT_VAL, INIT_SIZE, INIT_FFT are no longer macros, but are defined to be constant objects of particular classes. Their names do not change. ZZ_ARITH_RIGHT_SHIFT -> NTL_ARITH_RIGHT_SHIFT ZZ_BITS_PER_INT -> NTL_BITS_PER_INT ZZ_BITS_PER_LONG -> NTL_BITS_PER_LONG ZZ_DOUBLES_LOW_HIGH -> NTL_DOUBLES_LOW_HIGH ZZ_DOUBLE_PRECISION -> NTL_DOUBLE_PRECISION ZZ_EXT_DOUBLE -> NTL_EXT_DOUBLE ZZ_FDOUBLE_PRECISION -> NTL_FDOUBLE_PRECISION ZZ_FRADIX -> NTL_FRADIX ZZ_FRADIX_INV -> NTL_FRADIX_INV ZZ_FetchHiLo -> NTL_FetchHiLo ZZ_FetchLo -> NTL_FetchLo ZZ_HI_WD -> NTL_HI_WD ZZ_LO_WD -> NTL_LO_WD ZZ_MAX_INT -> NTL_MAX_INT ZZ_MAX_LONG -> NTL_MAX_LONG ZZ_MIN_INT -> NTL_MIN_INT ZZ_MIN_LONG -> NTL_MIN_LONG ZZ_NBITS -> NTL_NBITS ZZ_NBITSH -> NTL_NBITSH ZZ_NBITS_MAX -> NTL_NBITS_MAX ZZ_NTL_SINGLE_MUL_OK -> NTL_SINGLE_MUL_OK ZZ_PRIME_BND -> NTL_PRIME_BND ZZ_RADIX -> NTL_RADIX ZZ_RADIXM -> NTL_RADIXM ZZ_RADIXROOT -> NTL_RADIXROOT ZZ_RADIXROOTM -> NTL_RADIXROOTM ntl_eq_matrix_decl -> NTL_eq_matrix_decl ntl_eq_matrix_impl -> NTL_eq_matrix_impl ntl_eq_vector_decl -> NTL_eq_vector_decl ntl_eq_vector_impl -> NTL_eq_vector_impl ntl_io_matrix_decl -> NTL_io_matrix_decl ntl_io_matrix_impl -> NTL_io_matrix_impl ntl_io_vector_decl -> NTL_io_vector_decl ntl_io_vector_impl -> NTL_io_vector_impl ntl_matrix_decl -> NTL_matrix_decl ntl_matrix_impl -> NTL_matrix_impl ntl_pair_decl -> NTL_pair_decl ntl_pair_eq_decl -> NTL_pair_eq_decl ntl_pair_eq_impl -> NTL_pair_eq_impl ntl_pair_impl -> NTL_pair_impl ntl_pair_io_decl -> NTL_pair_io_decl ntl_pair_io_impl -> NTL_pair_io_impl ntl_vector_decl -> NTL_vector_decl ntl_vector_default -> NTL_vector_default ntl_vector_impl -> NTL_vector_impl ntl_vector_impl_plain -> NTL_vector_impl_plain BB_HALF_MUL_CODE -> NTL_BB_HALF_MUL_CODE BB_MUL_CODE -> NTL_BB_MUL_CODE BB_REV_CODE -> NTL_BB_REV_CODE BB_SQR_CODE -> NTL_BB_SQR_CODE FFTFudge -> NTL_FFTFudge FFTMaxRoot -> NTL_FFTMaxRoot FFTMaxRootBnd -> NTL_FFTMaxRootBnd QUAD_FLOAT_SPLIT -> NTL_QUAD_FLOAT_SPLIT WV_NTL_RANGE_CHECK_CODE -> NTL_WV_RANGE_CHECK_CODE WordVectorExpansionRatio -> NTL_WordVectorExpansionRatio WordVectorInputBlock -> NTL_WordVectorInputBlock WordVectorMinAlloc -> NTL_WordVectorMinAlloc XD_BOUND -> NTL_XD_BOUND XD_BOUND_INV -> NTL_XD_BOUND_INV XD_HBOUND -> NTL_XD_HBOUND XD_HBOUND_INV -> NTL_XD_HBOUND_INV ZZ_pRegister -> NTL_ZZ_pRegister ZZ_pX_BERMASS_CROSSOVER -> NTL_ZZ_pX_BERMASS_CROSSOVER ZZ_pX_DIV_CROSSOVER -> NTL_ZZ_pX_DIV_CROSSOVER ZZ_pX_FFT_CROSSOVER -> NTL_ZZ_pX_FFT_CROSSOVER ZZ_pX_GCD_CROSSOVER -> NTL_ZZ_pX_GCD_CROSSOVER ZZ_pX_HalfGCD_CROSSOVER -> NTL_ZZ_pX_HalfGCD_CROSSOVER ZZ_pX_NEWTON_CROSSOVER -> NTL_ZZ_pX_NEWTON_CROSSOVER ZZ_pX_TRACE_CROSSOVER -> NTL_ZZ_pX_TRACE_CROSSOVER zz_pRegister -> NTL_zz_pRegister zz_pX_BERMASS_CROSSOVER -> NTL_zz_pX_BERMASS_CROSSOVER zz_pX_DIV_CROSSOVER -> NTL_zz_pX_DIV_CROSSOVER zz_pX_GCD_CROSSOVER -> NTL_zz_pX_GCD_CROSSOVER zz_pX_HalfGCD_CROSSOVER -> NTL_zz_pX_HalfGCD_CROSSOVER zz_pX_MOD_CROSSOVER -> NTL_zz_pX_MOD_CROSSOVER zz_pX_MUL_CROSSOVER -> NTL_zz_pX_MUL_CROSSOVER zz_pX_NEWTON_CROSSOVER -> NTL_zz_pX_NEWTON_CROSSOVER zz_pX_TRACE_CROSSOVER -> NTL_zz_pX_TRACE_CROSSOVER ntl-11.5.1/doc/tour-ack.html0000644417616742025610000000502314064716023017336 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Acknowledgements

[Previous] [Up] [Next]

A Tour of NTL: Acknowledgements


  • Thanks to Arjen Lenstra and Keith Briggs for letting me use their software. Arjen Lenstra wrote LIP, a long integer package, which formed the basis of NTL. Keith Briggs developed a quadratic precision package. NTL has incorporated parts of these two packages, although what is in NTL has been extensively re-written. Thanks also to Keith for many helpful comments and suggestions.
  • Thanks to Juergen Gerhard for pointing out the deficiency in the NTL-1.0 ZZX arithmetic, for contributing the Schoenhage/Strassen code to NTL 1.5, and for helping to track down some bugs.
  • Thanks to Phong Nguyen for putting the new LLL code (NTL 1.7) through a torture test of lattices arising from new lattice-based cryptosystems; this led to a number of significant improvements in the LLL code.
  • Thanks to Dan Boneh for encouraging me to improve NTL's programming interface.
  • Thanks to John Abbott, Mark van Hoeij, and Paul Zimmermann for sharing many of their ideas about polynomial factoring over ZZ with me, which led to a number of improvements in NTL's factorizer. Thanks also to Paul for numerous other suggestions and improvements.
  • Thanks to Joachim von zur Gathen and Erich Kaltofen for their collaboration and support over the years.
  • Thanks to David Harvey for numerous improvements to NTL's FFT code. The current version of NTL's FFT is derived from code originally written by David.
  • Thanks to Luis Felipe Tabera Alonso for porting the fast GCD and XGCD code to GF2EX, zz_pEX, and ZZ_pEX, and for testing and tuning the code.
ntl-11.5.1/doc/tour-intro.html0000644417616742025610000000646414064716023017745 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Introduction
[Previous] [Up] [Next]

A Tour of NTL: Introduction


NTL is a high-performance, portable C++ library providing data structures and algorithms for arbitrary length integers; for vectors, matrices, and polynomials over the integers and over finite fields; and for arbitrary precision floating point arithmetic.

NTL provides high quality implementations of state-of-the-art algorithms for:

  • arbitrary length integer arithmetic and arbitrary precision floating point arithmetic;
  • polynomial arithmetic over the integers and finite fields including basic arithmetic, polynomial factorization, irreducibility testing, computation of minimal polynomials, traces, norms, and more;
  • lattice basis reduction, including very robust and fast implementations of Schnorr-Euchner, block Korkin-Zolotarev reduction, and the new Schnorr-Horner pruning heuristic for block Korkin-Zolotarev;
  • basic linear algebra over the integers, finite fields, and arbitrary precision floating point numbers.

NTL's polynomial arithmetic is one of the fastest available anywhere, and has been used to set "world records" for polynomial factorization and determining orders of elliptic curves.

NTL's lattice reduction code is also one of the best available anywhere, in terms of both speed and robustness, and one of the few implementations of block Korkin-Zolotarev reduction with the Schnorr-Horner pruning heuristic. It has been used to "crack" several cryptosystems.

NTL can be easily installed in a matter of minutes on just about any platform, including virtually any 32- or 64-bit machine running any flavor of Unix, Mac OS, or Windows. NTL can be built in conjunction with GMP (the GNU Multi-Precision library) for enhanced performance (this is the default on Unix and Mac OS). NTL can also be built in conjunction with the gf2x library for faster arithmetic of large degree polynomials over GF(2).

NTL provides a clean and consistent interface to a large variety of classes representing mathematical objects. It provides a good environment for easily and quickly implementing new number-theoretic algorithms, without sacrificing performance.

NTL is written and maintained by Victor Shoup with some contributions made by others (see Acknowledgements).

Lincensing: LGPLv2.1+

NTL is free software, and may be used according to the terms of the GNU Lesser General Public License version 2.1 or later.

[the precise licensing information of NTL]

[more information about GNU Licenses]

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-time.html0000644417616742025610000000611014064716023017534 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Some Performance Data
[Previous] [Up] [Next]

A Tour of NTL: Some Performance Data


Here are some timing figures from using NTL. They were obtained using NTL 11.0.0 compiled with g++ 4.8.5 and with GMP 6.1 on a 2.3GHz Intel Haswell processor (E5-2698 v3) running Linux.

All times are ins seconds. The times were obtained using the program Timing included in the distribution. The data was generated using NTL's random number generator, but running this on a different machine should (in theory) generate the same data.


multiply 1000-bit ints: 1.77903e-07
square 1000-bit ints: 1.08537e-07
remainder 2000/1000-bit ints: 3.58799e-07
gcd 1000-bit ints: 2.86069e-06
xgcd 1000-bit ints: 4.27161e-06
power mod 1000-bit ints: 0.000424325
multiply degree-1000 poly mod 1000-bit prime: 0.0041019
remainder degree-2000/1000 poly mod 1000-bit prime: 0.0119166
preconditioned remainder degree-2000/1000 poly mod 1000-bit prime: 0.00418589
gcd degree-1000 poly mod 1000-bit prime: 0.122145
multiply degree-1000 int poly with 1000-bit coeffs: 0.00467749

factoring degree-1000 poly mod 1000-bit prime...
square-free decomposition...0.119126
factoring multiplicity 1, deg = 1000
computing X^p...6.89619
computing DDF...generating baby steps...+++++++++++++++++++++2.72505
generating giant steps...++++++++++++++++++++++2.82554
giant refine...++++split 1 18
*++++*++++*++++*++++split 17 355
*split 0 627
giant refine time: 4.09811
baby refine...split 1 1
split 8 8
split 9 9
split 355 355
split 627 627
baby refine time: 0.037111
DDF time: 9.6903
...total time = 16.7138

multiply 500-bit GF2Xs: 5.3414e-08
remainder 1000/500-bit GF2Xs: 8.19842e-07
gcd 500-bit GF2Xs: 3.57209e-06

factoring degree-500 GF2X: 0.000154251
gcd 500-bit GF2X: 3.55401e-06
multiply degree-500 poly mod 500-bit GF2X: 0.00247313
remainder degree-1000/500 poly mod 500-bit GF2X: 0.00889548
preconditioned remainder degree-1000/500 poly mod 500-bit GF2X: 0.00498747
gcd degree-500 poly mod 500-bit GF2X: 0.0451361

factoring degree-500 poly mod 500-bit GF2X...
square-free decomposition...0.004369
factoring multiplicity 1, deg = 250
computing X^p...0.478202
computing DDF...generating baby steps...++++++++++0.329912
generating giant steps...+++++++++++0.355037
giant refine...++++split 1 9
split 2 13
split 4 44
*++++split 7 73
*split 0 111
giant refine time: 0.230542
baby refine...split 9 9
split 13 13
split 44 44
split 73 73
split 111 111
baby refine time: 0.001228
DDF time: 0.916753

...total time = 1.39667

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-changes.html0000644417616742025610000032012614064716023020214 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Summary of Changes
[Previous] [Up] [Next]

A Tour of NTL: Summary of Changes


2021.06.23: Changes between NTL 11.5.0 and 11.5.1

  • Fixed bug that prevented compilation on IBM Z.


2021.06.20: Changes between NTL 11.4.4 and 11.5.0

  • Added a new configuration option NTL_RANDOM_AES256CTR. The default is off. Configure with NTL_RANDOM_AES256CTR=on to replace the default ChaCha20 Pseudo-Random Number Generator (PRNG) with 256-bit AES counter mode. On certain plaforms (modern x86 and IBM System/390x), special instructions are exploited to improve performance.

    Using AES in place of ChaCha may break inter-operability of applications that depend on the behavior of the PRNG.

    Using AES in place of ChaCha may affect the performance positively or negatively. On IBM System/390x, there is a marked performance improvement. On x86 there may be a moderate performance improvement or degredation. On any other platforms, where there is no hardware support for AES (or none that is exploited by NTL), there will likely be a marked performance degredation.

    Thanks to Patrick Steuer for contributing this code.


2021.03.05: Changes between NTL 11.4.3 and 11.4.4

  • Improved Karatsuba code for ZZX and GF2EX (as well as the non-GMP implementation of ZZ). (Thanks to Marco Bodrato)


2020.01.04: Changes between NTL 11.4.2 and 11.4.3

  • Fixed bug in build logic that prevented compilation when not using gf2x library.


2019.12.31: Changes between NTL 11.4.1 and 11.4.2

  • Fixed gf2x library usage so that it now works with gf2x-1.3.
  • Fixed a bug in FFT.cpp that could be triggered when compiling in some legacy modes.
  • Added KarMul and KarSqr for ZZ_pX (declared in ZZX.h and implemented in ZZX.cpp). These are not a part of the documented interface.
  • A few other minor internal modifications.


2019.10.08: Changes between NTL 11.4.0 and 11.4.1

  • Fixed bug in new NTL_EXEC_DIVIDE that could manifest itself when NTL_THREAD_BOOST=off. Existing code that does not explicitly use this feature should not be affected by this bug.
  • Fixed some namespace visibility issues in the TLS hack macros.


2019.09.24: Changes between NTL 11.3.4 and 11.4.0

  • The Schoenhage-Strassen FFT for both ZZ_pX and ZZX is now fully "thread boosted". Here is a snapshot of performance, based on multiplying two polynomials of degree less than 8000 with 8000-bit coefficients. For ZZ_pX:
        # threads   time (ms)   effectiveness
        1           606   
        2           310         97%
        4           168         90%
        8           103         74%
    
    For ZZX:
        # threads   time (ms)   effectiveness
        1           461 
        2           247         93%
        4           144         80%
        8            96         60%
    

  • Introduced new tools for applying thread pools to divide and conquer algorithms. See NTL_EXEC_DIVIDE in BasicThreadPool.txt.
  • Fixed a few other minor issues.


2019.09.07: Changes between NTL 11.3.3 and 11.3.4

  • Changed NTL's build system so that if NTL_THREADS=on (which is the default) and SHARED=on (which is not the default), NTL's makefile will now pass -lpthread to libtool when it builds the library. On most platforms, this should allow users to forgo passing the -pthread option to their compiler when linking.
  • Made the build system's check of correct multithreading behavior a bit more robust.


2019.09.02: Changes between NTL 11.3.2 and 11.3.3

  • Changed "TLS hack" implementation to use fewer pthread keys (I did not realize these were a "scarce resource").
  • Implemented xdouble to double conversion to be more efficient for exponents of large magnitude.
  • Changed some internal interfaces (for FFTRoundUp) to be simpler and (in rare circumstances) to yield somewhat more efficient code.


2018.11.15: Changes between NTL 11.3.1 and 11.3.2

  • Fixed a somewhat embarrassing performance issue in the PowerMod function for the ZZ class (which also impacts the prime testing and generation functions). When using GMP, NTL will now call GMP's mpz_powm function. Although GMP does have an mpn_pown function, it is not documented, and so cannot be used by NTL. This means that NTL is now using some mpz-level functionality, in addition to mpn-level functionality.
    • This leads to a significant speedup (sometimes 2-3x), especially for numbers with a small number of limbs.
    • Thanks to Niek Bouman for helping to sort this out.


2018.10.20: Changes between NTL 11.3.0 and 11.3.1

  • Fixed a bug that effected image, kernel, and gauss routines for Mat<zz_p>. These routines did not behave correctly when the input matrix was zero. Also improved the mat_lzz_pTest program.


2018.08.17: Changes between NTL 11.2.1 and 11.3.0

  • Implemented an AVX-based small-prime FFT (which works with both AVX2 and AVX512)
    • This can give a 2-3x speedup for the FFT.
    • However, it is not enabled by default, because it reduces that small-prime size bound from 60 bits to 50 bits, and may slow down certain computations.
    • The reasons for this unfortunate slowdown are that some CRT-based computations may slow down because of the smaller prime size, and because Intel CPUs may slow themselves down when executing AVX instructions.
    • To enable this feature, configure with NTL_ENABLE_AVX_FFT=on.
    • Here are some running times on a Skylake Xeon machine (Intel(R) Xeon(R) Gold 6132 CPU @ 2.60GHz). For various values of n, we measure the time to compute ae mod f, where f is a random monic polynomial of degree n over Z17, a is a random polynomial of degree less than n, and e=2n-1.
         n           1024    2048    4096    8192   16384
         non-AVX    0.171   0.741   3.192  14.348  60.812
         AVX512     0.089   0.372   1.648   7.740  35.588
      

  • Implemented AVX512 instruction sequences
    • This affects Mat<zz_p> arithmetic and the small-prime FFT.
    • Becuause AVX512 instructions can in certain situations lead to slower computations (because of CPU "throttling"), this feature can be disabled by configuring with NTL_AVOID_AVX512=on.

  • Performance tuned GF2EX arithmetic
    • Tuned crossovers for various algorithms.

  • Implemented asymptotocially fast GCD and XGCD for GF2EX, zz_pEX, and ZZ_pEX
    • Some work may still need to be done to fine tune the crossovers, but they should be pretty good as is.
    • Many thanks to Luis Felipe Tabera Alonso for porting the code, as well as testing and tuning it.

  • Other small changes
    • Restructured quad_float implemenation to isolate better the parts that are dependent on correct FP rounding.
    • Standardized vector growth rate to 1.5 via the function _ntl_vec_grow.
    • Got rid of most uses of __restrict in mat_lzz_p.cpp, some of which were technically UB.
    • Got rid of some uses of #warning, which are not portable.


2018.07.15: Changes between NTL 11.2.0 and 11.2.1

  • Fixed an embarrassing bug, introduced in NTL 11.2.0, in which add(ZZ,ZZ,long) and sub(ZZ,ZZ,long) would give incorrect result if third argument was zero.
  • Fixed incorrect libtool version number in NTL 11.2.0.


2018.07.07: Changes between NTL 11.1.0 and 11.2.0

  • Complete re-write of the Schoenhage-Strassen FFT for ZZX arithmetic.
    • Implementation of "truncated" FFT
    • Implementaion of "sqrt 2" trick
    • More efficient implementation of low-level butterfly operations
    • Here is some timing data comparing ZZX multiplication times of NTL 11.0 and 11.2. The entries are the ratio of the 11.0-time over the 11.2-time (so the bigger the number, the bigger the improvement). The rows are labeled by the bit-length k of the coefficient, the column by the degree bound n. Unlabeled columns represent degree bounds half-way between the labeled ones.

    • For multiplication in ZZX, NTL and FLINT now have comparable performance across a wide range of parameter sizes, with NTL being 2x faster for some parameters, and FLITNt being 1.5x faster in others. Here is a chart showing the ratio of FLINT time over NTL time (so the bigger the number, the faster NTL is relative to FLINT)

    • See also this report on NTL vs FLINT for detailed benchmarks that compare the performance NTL and FLINT on a number of operations and parameter settings.
    • Future plans for NTL's Schoenhage-Strassen code:
      • Implement something like Bailey's 4-step variant (which should yield better cache behavior)
      • Thread boosting (built on top of the 4-step variant)
  • Some fine tuning of the new small-prime truncated-FFT implementation introduced in version 11.0.
  • Fixed obscure bug in new small-prime FFT code: this only affects users who call low-level, undocumented FFT routines on transforms of size 2, so it is unlikely to have affected any real code.
  • Performance improvements to ZZ+long and ZZ-long routines (and by extension ZZ+=long, ZZ-=long, ZZ++, and ZZ--)


2018.06.07: Changes between NTL 11.0.0 and 11.1.0

  • Complete re-write of the low-level "small-prime" FFT (a.k.a., NTT).
    • This implements a "truncated" FFT, which can speed up polynomial multiplication by a factor of two, and which mainly eliminates "jumps" in the running time at powers of two. The new FFT routines are in fact a bit faster even at powers of two.
    • Some low-level interfaces have changed, but these are all undocumented, so should not cause any problems for clients that don't inappropriately use such interfaces.
    • Here is some timing data comparing the new (truncated) FFT to the old (plain) FFT. x-axis is degree bound, y-axis is time (in seconds), shown on a log/log scale. This is the time to multiply two polynomials modulo a single-precision "FFT" prime (60 bits).

  • Improved performance of ZZ mul and sqr on small inputs
    • mul speedup: 1 limb: 2.5x; 2 limbs: 1.4x; 3 limbs: 1.3x.
    • NTL now makes explicit calls to mpn_sqr and requires GMP version 5.0 or later.

  • Other changes:
    • Changed header files to make Windows installation more reliable, especially for IDE's like Code Blocks
    • Added documentation for the GCD routine in the ZZ module
    • Fixed a bit of UB in the lip.h interface (_ntl_gbigint_body)


2018.04.07: Changes between NTL 10.5.0 and 11.0.0

  • Updated the configuration script:
    • It does some basic auto-detection of the compiler, default language standard, and hardware platform.
    • Using compiler information, it sets compiler flags affecting floating point more intelligently. Note also that the configuration and build scripts ensure that floating point closely adheres to the IEEE standard, and that the compiler does not perform any re-association.
    • Using the default language standard information, it sets the flags affecting language standards more intelligently.
    • Using the hardware platform information, it sets the TUNE flag more intelligently (in particular, on x86 platforms, the defaults should work just fine).
    • One now has to run ./configure to generate a make file, as the distribution no longer includes a default make file.
    • Running make clobber is no longer of much use, as the make file will call it automatically if you re-configure.
    • There is now a flag NTL_TLS_HACK that is automatically set by the configuration script. This flag controls how TLS (thread local storage) is implemented: either using pthread routines with __thread or using only thread_local. This flag replaces the NTL_DISABLE_TLS_HACK and NTL_ENABLE_TLS_HACK flags, which had to be set manually.
    • Added a flag NTL_DISABLE_MOVE_ASSIGN, which is on by default, and which prevents move assignment operators for Vec<T> and Mat<T>. This disables move assignment for many other classes, including all of the polynomial classes. Move assignment can break backward compatibility, as it may invalidate pointers into the destination vector. Move constructors are not affected.
    • Added a flag NTL_DISABLE_MOVE, which is off by default. This disables all move constructors and assignment operators. It is doubtful that this will ever be needed, except for really weird client code.
    • Added a check in the the build script to ensure that a thread-safe version of the gf2x library is used (if necessary).

  • Updated some default configuration values:
    • Made NTL_STD_CXX11=on the default.
    • Made NTL_THREADS=on and NTL_THREAD_BOOST=on the default. So now, by default, NTL is thread safe and exploits multiple cores to speed up many operations, when possible. To get these speedups, you just have to call SetNumThreads. See BasicThreadPool.txt for more details on thread boosting.
    • Made NTL_SAFE_VECTORS=on the default. This makes the use of NTL's vectors much safer, since they do not (by default) rely on the "relocatability" of the component type. This mode of operation has also been modified from previous versions so that it is more backward compatible (in particular, if the component type does not have a usable copy or move constructor, it can still work without compile-time errors). See vector.txt for more details.
      • All of the above new default settings require C++11 features. The configuration script will include additional compiler flags, such as -std=c++11, to ensure that these features are available. In addition, the NTL_THREADS=on and NTL_THREAD_BOOST=on settings generally require that the -pthread flag be passed to the compiler (at least on for GCC and GCC-like compilers). This means that to compile programs using NTL, you may have to pass the flags -std=c++11 and -pthread to your compiler (although, GCC version 6 and later do not require the -std=c++11, since the default is C++14 for these compilers).
      • If you really want to revert to the old default settings, run ./configure with
           NTL_STD_CXX11=off NTL_THREADS=off NTL_SAFE_VECTORS=off
        
    • Made NTL_CLEAN_PTR=on the default. This has no significant impact on performance, and avoids undefined behavior.
    • Made NTL_NO_INIT_TRANS=on the default. This means that functions returning class objects now rely exclusively on the "named return value optimization". Many years ago, one could not rely on this optimization, but nowadays, this optimization is essentially universal.

  • Performance improvements:
    • Thread boosted all cubic-time operations in mat_ZZ_pE, mat_lzz_pE, and mat_GF2E. This includes: matrix multiplication, inversion, determinant, kernel, image, and solving linear systems.
    • Thread boosted RandomPrime, GenPrime, and GenGermainPrime. Care has been taken so that on a given platform, you will always get the same prime if you run the algorithm with the same RandomStream. In particular, even though these routines are thread boosted, their behavior is independent of the number of available threads and any indeterminacy arising from concurrent computation. Also, care has been taken to ensure that the new algorithms are no slower than the old ones in a single-threaded environment.

  • New functionality:
    • Added a new function GetWallTime. See tools.txt for details.
    • Added a new function VectorRandomWord. See ZZ.txt for details.
    • Added support for true variadic templates in various smart pointer routines. See SmartPtr.txt for details.

  • Fixes and improvements to the Windows distribution:
    • The Windows distribution has the new default settings as described above. In particular, the new distribution is thread safe and thread boosted by default.
    • The distribution has been fixed so that certain linker errors no longer arise.
    • If the compiler is MSVC++, use of a long long type is enabled in certain settings for better performance.
    • Some basic testing was done using MSVC++ 2017 to ensure that the library works with the new default settings.


2017.07.07: Changes between NTL 10.4.0 and 10.5.0

  • Added uniform conversions from char* and const char*, which use whatever stream input operator >> applies.
    • For example, you can write conv(x, "...") or x = conv<T>("...") for x of any type T.
    • The code is written using templates in such a way that a second argument of 0 or nullptr will not match.
    • See conversions.txt for details.
  • Changed behavior of matrix input: non rectctanglar matrices set the fail bit on the stream, rather than raising an error
  • Fixed a benign error on make check.


2017.06.19: Changes between NTL 10.3.0 and 10.4.0

  • Faster linear algebra over ZZ_p. Rewrote mat_ZZ_p routines inv, solve, determinant, gauss, and kernel to be thread boosted (and inv was more extensvely rewritten, so it's a bit faster even without multi-threading.
    • I would still like to write reductions to matrix multiplication for many of these routines.

  • Faster pseudo-random number generation. Made the pseudo-random number generator (based on "Salsa20") faster on machines that support SSE3, and even faster on machines that support AVX2 (speedup with AVX2 is about 4.6x).
    • Hardware support is automatically detected at build time.
    • I had to downgrade the exception guarantees for RandomStream methods from "nothrow" to "strong ES".

  • C++11 support / "move" semantics. Added configuration flags NTL_STD_CXX11 and NTL_STD_CXX14.
    • Setting these flags will allow NTL to exploit certain language features guaranteed by the standard.
    • The NTL_STD_CXX11 will automatically be set by setting other configuration flags that require C++11 support.
    • If the NTL_STD_CXX11 flag is set, then NTL will declare "move" constructors and assigment operators for most of the major NTL classes. to the extent possible, these are declared "noexcept".
      • NOTE: by not enabling exceptions with NTL_EXCEPTIONS=on, you get more "noexcept" move constructors, which can yield better performance.

  • Safe vector mode. Added a new "safe vector" mode, which is enabled with NTL_SAFE_VECTORS=on. In this mode, NTL relaxes the "relocatability" requirement for NTL vector types. While this flag is currently "off" by default, I expect that at some point in the next couple of years, it will be "on" by default.
    • More details available here.
    • This feature requires C++11.

  • Iterators and support for "range based for loops". Added a "proxy iterator" to the Vec<GF2> class. With this, now all the Vec<T> classes have iterators, which means that you can use the C++11 syntax for "range based for loops". The safest way to write these for loops in general is as:
      for (auto&& item : vec) { ... }
    

  • Convenience routines for random vectors and matrices.
    • Added convenience routines random(vec, n) to build a random vector vec of length n. Available for vectors over GF2, GF2E, zz_p, zz_pE, ZZ_p, and ZZ_pE.
    • Added convenience routines random(mat, n, m) to build a random n-by-m matrix mat. Available for matrices over GF2, GF2E, zz_p, zz_pE, ZZ_p, and ZZ_pE.


2016.11.18: Changes between NTL 10.2.0 and 10.3.0

  • Implementation of a multi-modular strategy for matrix multiplication over ZZ_p. Here are some benchmarks that compare the new strategy to the old (naive) one. Here, we consider n-by-n matrices modulo an n-bit prime.
    • n=128, speedup=6.8x
    • n=256, speedup=8.6x
    • n=512, speedup=9.3x
    • n=1024, speedup=18x
    • n=2048, speedup=37x

    I also compared NTL's new mat_ZZ_p multiplication to FLINT's fmpz_mat multiplication. The latter also uses a multi-modular strategy. For n=128,256,512,1024 as above, NTL's code is between 2.7 and 3.1 times faster than FLINT's (and we did not count the time it would take to reduce the entries mod p for the FLINT code).

    Part of this may be due to the AVX-enhanced small-prime matrix multiplication code used by NTL, and part may be due to better CRT code.

  • I also instrumented both the plain and multi-modular matrix multiplication for ZZ_p so that they are both "thread boosted" (i.e., will automatcally exploit multiple cores when possible).

  • As an initial application of this faster matrix multiplication, I implemented a new version of Brent/Kung modular composition for ZZ_pX, which is now between 2 and 5 times faster than the old one (depending on parameters). This is done with a new class called ZZ_pXNewArgument, which supersedes ZZ_pXArgument (retained for compatibility). This also makes the CanZass factoring algorithm for ZZ_pX faster (sometimes by a factor of almost 2, depending on parameters). It also makes CanZass more memory intensive (but while the overall memory usage increases, the memory access pattern is fairly cache friendly).

  • I would like to see if this faster matrix multiplication can be used to get faster linear algebra (determinants, inverses, more general Gaussian elimination) via reduction to matrix multiplication. If anyone wants to volunteer to work on this, please let me know. Presumably, the FLINT nmod_mat code could be repurposed for this. I won't have time to work on this for a few months, but would be glad to discuss ideas with anyone who wanted to do the work. Note that the "plain" versions of these routines also need some work.

  • I also added move methods to the Vec and Mat classes, and made a slight tweak to the Lazy class.


2016.11.10: Changes between NTL 10.1.0 and 10.2.0

  • Added "thread boosting" to the ZZX multiplication routine. This can significantly increase performance on multicore machines (you must configure with NTL_THREAD_BOOST=on and call SetNumThreads).
  • Marginally improved performance and crossovers for mat_zz_p multipliplication.
  • Marginally improved performance for mat_ZZ_p multipliplication (but much bigger improvements hopefully coming soon).
  • Retired the zz_pXAltArgument class, which was used for modular composition in zz_pX. While this has been in in the documented interface for a few months, it was flagged as being provisional and subject to change. Well, it is being changed: it is being eliminated.
  • In place of zz_pXAltArgument, I've added a class zz_pXNewArgument. For the time being, this will also be provisional and subject to change. With this class, all the code complexity for improved performance of modular composition is relegated to mat_zz_p multiplication. Also, all modular composition in zz_pX in NTL goes through this new class. The old zz_pXArgument remains just for backward compatibility.


2016.10.14: Changes between NTL 10.0.0 and 10.1.0

  • Better building
    • Thanks to the encouragement and guidance of the Sage developers, I've made some improvements to the build process (this applies only to the Unix distribution -- Windows users still have to keep on pointing and clicking).
    • The build process now configures libtool on the fly, rather than relying on an existing libtool program. This should make builing dynamic libraries easier. Also added a configuration variable LIBTOOL_LINK_FLAGS, mainly to help with Cygwin builds.
    • Added a TUNE switch to the configure script.
      • TUNE=auto (the default) runs the performance-tuning wizard (as before).
      • TUNE=x86 skips the wizard and sets all performance-related flags so that they are geared towards (a not too old) x86 machine.
      • TUNE=generic skips the wizard and sets all performance-related flags so that they should not be too bad on any fairly modern machine (PowerPC, ARM).
      Additional tuning values may be set in the future. The source files have also been adjusted to accomodate this feature: if a performance option requires some hardware/software feature that is not available, the performance option is quietly ignored.
    • Fixed the makefile so that recursive invocations call $(MAKE) rather than make.
    • With these improvements, then on the 32-core Haswell server I've been using lately, if I type
         % configure TUNE=x86
         % make -j20
      
      then the whole business of configuring and building NTL takes less than a minute :-).
    • There are a number of other small improvements to the build process.
    • [See here] for more details (this documentation is now hopefully more informative as well).

  • Vec tweaks
    • Made some small tweaks to the Vec class.
    • The copy constructor for Vec<T> no longer requires an assgnment operator for T.
    • Started laying the groundwork for a possible future implementation that would do something about about the "relocatabilty" requirement for vector element types. In theory, this is a very thorny issue, and the current implementation is somewhat dangerous. In practice, this implementation has served its purpose quite well for about 25 years. Still, it would be nice to tighten things up a bit, without affecting performance.

      It would be great to discuss these issues with any C++ experts out there!


2016.10.08: Changes between NTL 9.11.0 and 10.0.0

  • New License: LGPLv2.1+
    • With the permission of all relevant contributors, NTL is now licensed under LGPLv2.1+ (the Lesser GNU Public License version 2.1 or later).
    • Previously, NTL was licensed under the GPL. This new, less restrictive licensing should hopefully increase the impact of NTL.

  • Long integer package restructing
    • I've restructured the long integer package so that the GMP and "classical LIP" modules share much of the same code base.
    • This greatly reduces the amount of redundant code, which will make maintenance easier moving forward.
    • As a bonus, the classical LIP module is simpler, faster, and (finally) thread safe.
    • As another bonus, the GMP module now is much closer to being compatible with "non-empty nails". Although it has not been tested in that mode as of yet, it may eventually be helpful in the future if I want to replace some GMP code with code that exploits AVX-512 IFMA instructions.
    • As a part of this transition, "make check" now includes much more extensive "unit testing" of the long integer package.
    • Despite the drastic changes "under the hood", this restructuring should not affect at all any NTL client code that relies only on the documented interface, including even the ancient legacy interfaces pre-dating NTLv5a from 2000.

  • File name restructuring
    • I've renamed all the ".c" files to ".cpp" files in the Unix distribution. This seems to be more in line with common practice, and should make it easier to work with compilers and other software development tools.


2016.08.22: Changes between NTL 9.10.0 and 9.11.0

  • Improved the effectiveness of the new, faster ZZ to zz_p conversion
  • Added new routines VectorConv for faster bulk conversion from ZZ and long to zz_p (see lzz_p.txt)
    • There are some hidden interfaces which could be more generally useful, and I may add these to the documented interface at some point.
  • Added new routines VectorRandomBnd (see ZZ.txt) and VectorRandom (see lzz_p.txt) for faster bulk random number generation
    • Again, there are some hidden interfaces which could be more generally useful, and I may add these to the documented interface at some point.


2016.06.21: Changes between NTL 9.9.1 and 9.10.0

  • Fixed a problem in the aligned array logic that prevented compilation on MinGW on Windows.
  • Conversions from ZZ to zz_p are now faster, thanks to preconditioning. Among other things, the CRT-based ZZX multiplication code is also a bit faster as a result.
  • The BasicThreadPool class now guarantees that exec_range assigns the current thread first=0, and exec_index assigns the current thread index=0. This makes it easy for a thread to tell whether of not it is the current thread, which can be convienient for some applications.
  • Fine tuned the interface for SmartPtr and UniquePtr a bit, including the ability to attach an explicit deleter policy, which (among other things) makes it easier to implement the PIMPL pattern using these classes. Unfortunately, some of these changes introduced some minor backward incompatibilities (but I doubt anyone will even notice).
  • Introduced a new class CopiedPtr, which has a similar interface to UniquePtr, but which allows copy and assignment. This class is meant to replace the OptionalVal class, whose use is now discouraged.


2016.06.02: Changes between NTL 9.9.0 and 9.9.1

  • Fixed a bug in NTL_EXEC_INDEX (actually, in BasicThreadPool::relaxed_exec_index) that would cause an error to be incorrectly raised in some situations
  • Fine tuned some crossover points


2016.05.30: Changes between NTL 9.8.1 and 9.9.0

  • Added examples on how to use documentation on NTL's thread pools and parallel for loops: see here
  • The build procedure now puts files config_log.h and wizard_log.h in NTL's include directory. These files contain comments that document what choices were made during the build process, including the CXXAUTOFLAGS value.
  • Added elts() method to UniqueArray and AlignedArray (for compatibility with Vec class)
  • Added get() and release() methods to OptionalVal
  • Made constructors for PartitionInfo and BasicThreadPool explicit
  • Cleaned up some pointer issues in mat_lzz_p.c (mainly academic)
  • Definition of NTL_TLS_LOCAL_INIT ensures that var names a local reference, regardless of the implementation
  • Allow p.move(q), where p is a UniquePtr<T>, q is a UniquePtr<Y>, and Y* converts to T*.
  • Introduced PreconditionedRemainder class for faster reduction of a ZZ modulo a fixed long. This is intended to make Chinese Remaindering type computations faster
    • for the time being, this is an undocumented feature which may be modified or removed in a future release
  • Introduced ll_type and related routines which perform a restricted set of operations on a long-long-like type. It can be implemented via inline asm, and is a cleaner interface and sometimes faster. On x86-64/gcc platforms, the assembly code version is used and gives a modest speed boost. For all other platforms (including x86-64 with clang or icc), the assembly code is not used. I should really dynamically enable the assembly via the performance tuning wizard, but I don't do this yet. To explicitly disable the assembly code, configure with NTL_DISABLE_LL_ASM=on.
    • for the time being, this is an undocumented feature which may be modified or removed in a future release


2016.04.29: Changes between NTL 9.8.0 and 9.8.1

  • Fixed an annoying issue that could cause a unnecessary ambiguities in client code when compiling with NTL_EXCEPTIONS=on


2016.04.26: Changes between NTL 9.7.1 and 9.8.0

  • Thread safety for the masses!
    • Previous versions of NTL required full C++11 compliance to achieve thread safety
    • Unfortunately, many platforms (notably, Mac OSX) do not provide the necessary features - in particular, they do not provide full, correct support for "thread local storage" (TLS)
    • This new release (by default) will apply a "TLS hack" that works around this limitation (at least for gcc and gcc-compatible compilers such as clang and icc)
      • With this "hack", it is only required that gcc's more widely available __thread storage specifier be implemented, rather than the less widely available thread_local specifier (and it also makes direct use of the pthread library)
      • You can explicitly disable the hack by configuring NTL with NTL_DISABLE_TLS_HACK=on
    • This "hack" has been successfully tested on Linux with gcc 4.8.5 and on Mac OSX 10.10 and 10.11 with clang
      • It should work with any gcc 4.8.x or higher
      • Many thanks to Justin Walker for pushing this issue and helping with the Mac OSX testing
  • Fixed a "pseudo" bug in the test script: BitMatTest in make check was reporting "failure", but this was a bug in BitMatTest, not in NTL itself.

  • Fixed a real bug in the ReleaseThreadPool function (although NTL internally does not use this function, so only client code that called it directly would be affected).


2016.04.20: Changes between NTL 9.7.0 and 9.7.1

  • Extended the performance improvements in mat_lzz_p to include the gauss, kernel, and image routines
  • Generally improved performance for all of the mat_lzz_p, including an implementation of Strassen for matrix multiplication.
  • Added the matrix/column vector solve routines to all other matrix classes (for consistency).

  • Fixed a compile-time bug that occured on certain platforms (mainly Windows).
  • Made some of the steps in configure and make a bit more quiet (look at .log files for outputs).


2016.03.12: Changes between NTL 9.6.4 and 9.7.0

  • Changes to mat_lzz_p module:
    • Improved performance of mul, inv, solve, and determinant routines:
      • more cache friendly
      • thread boosted
      • for small p (up to 23 bits), exploits AVX and FMA instructions (when available)
      • depending on many things, the new code can be anywhere between 1.5x and 70x (!) times faster than the old code (part of that speedup up can be attributed to just how awful some of the old code was, rather than how brilliant the new code is)
      • on the SandyBridge and Haswell machines I was able to test, the new code is comparable in speed to FFLAS/FFPACK
    • Added "relaxed" versions of inv, solve, and determinant, which also now work for prime powers, not just primes
    • Added a new variant of solve routine to solve A*x = b for column vectors

  • Changes to BasicThreadPool module:
    • Added NTL_EXEC_RANGE and other functionality which makes writing "parallel for loops" simple (very similar to OpenMP), and the same source code will work regardless of whether threads or thread boosting is enabled.
    • Backward incompatibilities:
      • NTLThreadPool is no longer directly accessible: new access functions are provided
      • Got rid of method SplitProblems, and made a more general/abstract class PartitionInfo

  • Miscellaneous:
    • Improved crossover points for GF2X division
    • Made access to thread local variables used in NTL faster by using GCC's __thread in place of thread_local, wherever possible
    • Improved performance of vec_long to vec_zz_p conversion
    • Made AVX and FMA detection more robust, requiring LP64
    • Added InvModStatus for long's
    • Bumped FILE_THRESH to 1e12


2016.01.30: Changes between NTL 9.6.3 and 9.6.4

  • Streamlined some of the installation scripts, so now the "heurstic selection of compiler flags" and the "nonstandard feature testing" procedures are more structured so as to be easier to extend in the future -- it is beginning to act more like a sort of "autoconf".
  • Fixed a couple of "buglets" in the header files.


2016.01.26: Changes between NTL 9.6.2 and 9.6.3

  • Some changes to the installation procedure:
    • For the Unix distribution, NTL_GMP_LIP is now on by default, which means that by default, NTL will use GMP.
    • By default, the configuration script will attempt a "native'' build by passing -march=native as a compiler flag. Most modern compilers support this, but the configuration script will check to make sure.
    • The NTL_PCLMUL flag (which enables the use of Intel's PCLMUL instruction) is now automagically set by the Wizard script.
    • The build script automatically checks for availability of Intel AVX intrinsics, which may be used to better optimize certain code.
  • A new modular composition implemention for zz_pX. This makes modular composition up to 3x faster, depending on several factors.
  • Improved performance for polynomial factoring over zz_pX using CanZass, using the improved modular composition routine (above) and better choice of baby step / giant step parameters. This leads to a 1.1x to 1.8x speedup, depending on several factors.
  • Improved robustness of quad_float implementation: it should now work correctly on platforms that are too liberal in their use of FMA instructions.


2015.11.13: Changes between NTL 9.6.1 and 9.6.2

  • More small tweaks and a new configuration variable:
    NTL_MAXIMIZE_SP_NBITS=off
    
    # Allows for 62-bit single-precision moduli on 64-bit platforms.
    # By default, such moduli are restricted to 60 bits, which
    # usually gives *slightly* better performance across a range of
    # of parameters.
    


2015.11.13: Changes between NTL 9.6.0 and 9.6.1

  • Streamlined some awkard code in g_lip_impl.h.
  • Made QuickTest a bit quicker.
  • Fixed some documentation/packaging problems.


2015.11.10: Changes between NTL 9.5.0 and 9.6.0

  • More performance tuning for ZZ_pX arithmetic.
  • Added configuration variable CXXAUTOFLAGS, which is dynamically (and heuristically) set by the configuration script. This way, CXXFLAGS is not modified by the script.


2015.10.20: Changes between NTL 9.4.0 and 9.5.0

  • Added a new thread boosting feature. With this feature, certain code within NTL will use available threads to speed up certain computations on a multicore machine. This feature is enabled by setting NTL_THREAD_BOOST=on during configuration. See BasicThreadPool.txt for more information.

    This feature is a work in progress. Currently, basic ZZ_pX arithmetic has been thread boosted. More code will be boosted later.

  • A bit more perfomance tuning for ZZ_pX arithmetic, and better crossovers for ZZX multiplcation.


2015.9.22: Changes between NTL 9.3.0 and 9.4.0

  • Performance tuning: ZZ_pX and zz_pX keep getting faster
  • Upgrade to pseudo-random number generation: I replaced the underlying PRG with Chacha20 (replacing RC4) and the underlying key-derivation function with a function based on HMAC-SHA256 (replacing an MD5-based function). The new routines are faster and more secure.

    I also expanded the PRG interface a bit: see here for details.

  • Bug fixes: fixed a (mostly dormant) bug in the ZZFromBytes routine (triggered only when n==0).
  • Added documentation for classes RRPush and RROutputPush: see here for details.


2015.7.9: Changes between NTL 9.2.0 and 9.3.0

  • Fixed a compilation error that arose with NTL_LEGACY_SP_MULMOD=on.
  • Added a new call back routine ErrorMsgCallback. See tools.txt. This is mainly to help with NTL integration withing SAGE.


2015.5.23: Changes between NTL 9.1.1 and 9.2.0

  • Completed the transition away from floating-point arithmetic for the implementation of single-precision modular arithmetic. The current implementation should allow 60-bit moduli on 64-bit platforms that support a 128-bit extended integer type (this is the case for current gcc, clang, and icc compilers).

    One can still revert to the "classical" (pre-9.0) implementation using double-precision arithmetic (which imposes a 50-bit limit), or to the "long double" implementation introduced in v9.0 (60-bit limit).

    Note that one must compile NTL with GMP to get any of these improvements. It would have perhaps been better to use GMP's longlong.h facility instead of relying on compiler support for extended integer types. However, at the moment, it is a bit inconvenient to use longlong.h as a freestanding header file. This might change in the future.

    For details, see here, including the comments entitled "Compatibility notes".

    Programming notes: MulMod(a, b, n) is equivalent to mulmod_t ninv = PrepMulMod(n); MulMod(a, b, n, ninv). Compared to the older, floating-point implementation, the relative cost of computing ninv is higher in the new regime. In a loop where n is invariant, the compiler should "hoist" the computation of ninv, so it is only done once. However, it is usually better to precompute and store ninv, and use the second form of MulMod, with ninv passed as a parameter (NTL does this internally quite consistently). The performance of MulMod(a, b, n, ninv) is somewhat faster in the new implementation. Where possible, one should use MulModPrecon, which is faster still (useful in situations where both n and b are invariant).

  • A number of general performance improvements.


2015.5.16: Changes between NTL 9.1.0 and 9.1.1

  • Fixed a bug introduced in 9.1.0 that prevented conversions between Vec<GF2> and Vec<T>.


2015.5.2: Changes between NTL 9.0.2 and 9.1.0

  • Added a new configuration switch to enable the PCLMUL instruction on x86 machines. This can speed up GF2X arithmetic significantly (by a factor of 4). This is enabled by configuring with NTL_PCLMUL=on (and the configuration script automatically checks if it actually works on your platform).

    Note that this is an alternative to building NTL against the gf2x library (the latter is currently not thread or exception safe).

  • Performance improvements to zz_pX and Vec<zz_p>.

  • Performance improvements to ZZX: implemented asymptotically fast CRT code for HomMul and more cache-friendly logic. This routine is used for polynomials whose degree is significantly larger than the bit-length of its coefficients. This should make NTL's ZZX multiplication faster across a broader range of parameters, and at least be within a (hopefully not-too-large) constant factor of optimal.

  • Some internal cleaning on the small-prime FFT code. I've made David Harvey's lazy butterfly routine without precomputed tables more competitive with the large-table variant, so now that large tables are used for a smaller range of parameters (this should reduce the overall memory footprint).

  • Laid the groundwork for some future changes; namely, to allow 60-bit modular arithmetic without relying on the esoteric x87 fmul instruction. This should be coming soon (probably v9.2).


2015.3.29: Changes between NTL 9.0.1 and 9.0.2

  • Made a small change to single-precison MulMod that enables slightly better compiler optimizations (compiler can "hoist" the computation of 1/n out of a loop, so the variant with extra mulmod_t arg becomes somewhat less essential).


2015.3.27: Changes between NTL 9.0.0 and 9.0.1

  • Fixed a small bug that prevented compilation a certain platforms.


2015.3.27: Changes between NTL 8.1.2 and 9.0.0

  • With much trepidation, I have introduced a (hopefully minor) backward incompatibility into NTL. The interface to the single-precision modular arithmetic routines has been modified slightly. This interface change allows for more flexible and more efficient implementation of these routines, which play a crucial role at many levels in NTL.

    Basically, these changes to the interface abstract away some implementation details that arguably should never been there in the first place. By coding to the new interface, NTL clients will be able to benefit from the current and future improvements.

    In particular, on 64-bit x86/GCC platforms, single precision moduli can now be up to 60 bits, rather than 50 bits. While some operations may in fact be a little slower, the most important ones (like MulModPrecon) should not be. Using larger moduli speeds up a number of things, like ZZ_pX arithmetic, as fewer primes need to be used in Chinese Remaindering steps. Other applications benefit from larger moduli as well.

    It is expected that most NTL clients will not be affected at all. Moreover, any code that needs to be updated will be detected by the compiler, and the updates should be simple and mechanical. There is also a configuration flag that will enable the legacy interface (although this is not recommended practice).

    For details, see here, including the comments entitled "Compatibility notes".

  • Other changes:
    • Previous versions of NTL relied (at least by default) on some undefined behavior regarding integer arithemtic (namely, that in a few key code sequences, signed integer overflow just "wraps around"). All of this undefined behavior has been replaced by (much more desirable) implementation-defined behavior (namely, that conversion from unsigned to signed works as expected). As in the past, the NTL_CLEAN_INT can be used to avoid all of these issues (but with the new code, this should truly be academic). For details, look here.
    • By request, added a function xdouble exp(const xdouble& x), which is equivalent to xexp(to_double(x)). For details, look here.


2015.1.31: Changes between NTL 8.1.1 and 8.1.2

  • Corrected a bug that could affect the log function in a multi-threaded execution.


2015.1.30: Changes between NTL 8.1 and 8.1.1

  • Corrected a syntax error in SmartPtr.h, which most compilers don't seem to complain about, but some do.

  • Added --tag=CXX to the some lines in the makefile to keep libtool happy.


2015.1.9: Changes between NTL 8.0 and 8.1

  • Corrected an oversight in the matrix template class. With this new version, one may safely copy and assign objects of type Mat<ZZ_p> and Mat<GF2E> out of context (i.e., under a different or undefined modulus). More generally, the copy constructor for Mat<T> now relies only on the copy constructor for Vec<T> and the assignment operator for Mat<T> relies only on the assignment operator and copy constructor for Vec<T>.

    The goal since v6.2 has been to allow all modular types (ZZ_p, etc.) and all types derived from them (vectors, polynomials, matrices, etc.) to be safely copy constructed and assigned out of context. Hopefully, this goal has now been reached.


2014.12.24: Changes between NTL 7.0.2 and 8.0

  • Exceptions!

    This is another major milestone for NTL, and hence the big version number bump (this will be the last of these big bumps for a while).

    Prior to this version, error handling consisted of "abort with an error message". To enable exceptions in NTL, configure with NTL_EXCEPTIONS=on. You will also need a C++11 compiler for this to work properly (and if you don't enable exceptions, any old C++98 compiler will work, as always).

    With exceptions enabled, errors are reported by throwing an appropriate exception. Of course, this was the easy part. The hard part was making NTL's code exception safe, which (among other things) means that no resources (i.e., memory) are leaked when an exception is thrown. This required a very painful top-to-bottom scrub of the whole library.

    Despite major changes to the code base and many internal interfaces, the external (i.e., documented) interfaces remain completely unchanged.

    More details are available here.

  • Improved performance of ZZ_pX arithmetic for both classic and GMP-based long integer packages.

  • Made copy constructor and assignment operators for fftRep and FFTRep safe "out of context", which extends to the classes zz_pXModulus and ZZ_pXModulus.

  • Made mechanism for establishing "unique ID's" (used for temporary file name generation and default pseudo-random number seeds) more robust.


2014.12.15: Changes between NTL 7.0.1 and 7.0.2

  • Fixed bug introduced in v7.0 affecting RR and quad_float input routines, which would leave the RR precision variable in an incorrect state.

  • Fixed a bug introduced in the v6.2 that affected the append routines for ZZ_p and GF2E, which would lead to incorrect memory allocation (which, if triggered, should just have led to an error message and abort, rather than incorrect results). This bug also affected the new Vec constructor introduced in v7.0 (and again, only for ZZ_p and GF2E).


2014.11.14: Changes between NTL 7.0.0 and 7.0.1

  • Fixed critical bug in new bit-reverse-copy routine. Large degree polynomial multiplication code was buggy in v7.0. Now it's fixed and properly tested.


2014.11.8: Changes between NTL 6.2.1 and 7.0

  • Thread safety!

    This is a major milestone for NTL (and hence a bump in the major version number). However, to actually use it, you will need a "bleeding edge" C++ that supports C++11 concurrency features. Most importantly, the C++11 storage class thread_local needs to be fully and correctly implemented. Some compilers claim to support it, but are very buggy to the point of being useless. All I can say is, as of right now, I have been able to successfully build and test a multi-threaded NTL program using GCC 4.9.2 on a Red Hat Linux distribution. I don't think any pre-4.9.x version of GCC will work. And unfortunatly, I don't think any compiler (GCC or CLANG) on any current Mac will work, but I haven't been able to directly test this.

    As time goes on, I expect C++ compilers will provide the necessary support. In the meantime, you can try it out and see if it works for you. Configure with the NTL_THREADS flag turned on and see what happens. The test program ThreadTest that runs as the last step of make check will let you know if it works. If not, you can try building GCC 4.9.2 yourself. It is actually not that hard!

    See the portability and implementation section for more information. In any case, if threads don't work for you, just don't use them. Everything still works as before using almost any compiler.

  • I changed the stream input behavior to conform to wider C++ practice (and with an eye towards am exception safe future). Previously, if an attempt to read an NTL object failed, the good old Error function was called, printing an error message, and aborting your program. Now, NTL just quietly sets the ``fail bit'' of the stream. The second example here illustrates this. Hopefully, this change will not cause too many problems, but if it does, configure NTL with the NTL_LEGACY_INPUT_ERROR flag on to get the old behavior back.

  • To further simplify future development, I've dropped support for legacy C++ standard header files. That is, NTL always uses <iostream> rather than <iostream.h>. This shouldn't be a problem for anyone by now, as these lagacy header files have been gone from standard C++ since 1998. Also, by default, NTL components are still wrapped in the NTL namespace, but for backward compatibility, you can still put them in the global namespace by configuring NTL with the NTL_LEGACY_NO_NAMESPACE flag.

  • Implemented a cache-friendy "bit reverse copy" routine for doing FFT's. This is the COBRA algorithm from Cater and Gatlin, "Towards an optimal bit-reversal permutation algorithm", FOCS 1998. This does seem to help a bit. Getting rid of "bit reverse copy" would be even better, but this would take more work and break a number of interfaces.

  • Made some minor improvements to ZZX multiplication routines to get better locality of reference. Improvement is nominal.

  • Fixed a small issue in the left-shift ZZ routine: it was allocating one word more than necessary in some cases.

  • Added new Vec constructor, so

       T a;
       Vec<T> v(INIT_SIZE, n, a);

    is equivalent to

       T a;
       Vec<T> v;
       v.SetLength(n, a);

    In both cases, the copy constructor for T is used.

  • I've added some more documentation about what I plan on doing with NTL in the future, as well as a "wish list" of what I hope others might contribute. See the roadmap section for more details.


2014.8.26: Changes between NTL 6.2 and 6.2.1

  • Fixed syntax problem in NTL/vector.h


2014.8.21: Changes between NTL 6.1 and 6.2

  • I added explicit constructors corresponding to promotions. For example:

       ZZ w = ZZ(1); // legal
       ZZ w(1);      // legal
       ZZ w{1};      // legal in C++11
       ZZ w = 1;     // not legal

    Also added new names for the "monomial constructors", e.g., ZZX(INIT_MONO, i, c) is now preferred to ZZX(i, c), although the old constructors are still there. There are also new constructors like ZZX(INIT_MONO, i) for making monic monomials.

  • An subtle but important change is that now objects from classes that represent residue class rings with a dynamically installed modulus, i.e.,
       ZZ_p, zz_p, ZZ_pE, lzz_pE, GF2E,
    
    may now be used a bit more flexibly.

    It is critical that such objects created under one modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations now include: the default and copy constructor, the destructor, and the assignment operator. In addition it is generally safe to read any object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function). (In the past, it was generally unsafe to use the the default and copy constructors out of context, which also prevented vectors and polynomials of such objects from being copied out of context.)

    The implementations of Vec<ZZ_p> and Vec<GF2E> are still specialized to manage memory more efficiently than in the default implementation of Vec<T>. Contiguous elements in such an array are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on such a vector will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a such a vector using the default or copy contructor, and to assign or append one to another "out of context".

  • For the classes ZZ_p, ZZ_pE, zz_pE, and GF2E, added explicit "allocation" and "no allocation" contructors (invoked with INIT_ALLOC and INIT_NO_ALLOC) and special member function allocate(). This allows one to explicitly determine exactly when space for such objects is allocated. By default, no space is allocated (this is different from prior versions of NTL), except for ZZ_p's that are a part of a Vec<ZZ_p> and GF2E's that are a part of a Vec<GF2E>

  • Added new classes ZZ_pPush, ZZ_pEPush, zz_pPush, zz_pEPush, GF2EPush. These allow one to conveniently backup and optionally install a new modulus in one step:

       { ZZ_pPush push(p); ... }

    will save the current modulus and install p as the new modulus; when the destructor for push is invoked, the old modulus will be re-installed.

  • Made the one-arg constructors for all the various "context" classes (e.g., ZZ_pContext) explicit.

  • As a general aid to generic programming, I've added a bunch of typedef's using consistent naming conventions to all of the main arithmetic classes. E.g., ZZ_p::poly_type is a typedef for ZZ_pX. There are a whole bunch of these. See the documentation for the individual classes for details.

  • Got rid of a few esoteric compilation modes:
    • All files are now C++ files, and should be compiled using a C++ compiler. In older versions, some files could be compiled either as C or C++.
    • The flag NTL_GMP_HACK is no longer supported. GMP may still be used using the NTL_GMP_LIP flag, which is still highly recommended for high-performance applcations.
    • The flags NTL_SINGLE_MUL and NTL_FAST_INT_MUL are no longer recognized. These were really outdated and esoteric.

  • I have started working towards making NTL thread safe. It is not as difficult as I thought it would be, but it is still a work in progress. So far I have identified all global variables, and either got rid of them, or tagged them as "thread local". So, although there are still some global variables, they will all eventually be "thread local". In particular, things like the current ZZ_p modulus will be a thread-local global variable.

    There are a few remaining trouble spots I've tagged: these mostly involve lazy initialization of tables; I have a plan for making this code thread safe using nearly lock-free coding techniques.

    I will hopefully get this done within the next 6-12 months. One thing that is slowing me down is the lack of availibility of C++11 features that I need to do some of this, but it will come.

    The main reason for getting rid of the esoteric compilation modes mentioned above is to make it easier to do this thread-safety work.


2014.03.13: Changes between NTL 6.0 and 6.1

  • Added support for "user defined" FFT primes for zz_p. See the functions

       static void zz_p::UserFFTInit(long p);
       zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p);

    in the lzz_p module.


2013.02.15: Changes between NTL 5.5.2 and 6.0

  • Replaced the old template-like macros for vectors, matrices, and pairs with true template classes: Vec<T>, Mat<T>, and Pair<S,T>.

    For backwards compatibilty, all the names that were used in previous versions (e.g., vec_ZZ_p, mat_ZZ_p) have been replaced with appropriate typedefs.

    For many years, I resisted the temptation of using templates, because compiler support was very inconsistent. But that no longer seems to be the case.

    This change, while rather sweeping, should create very few, if any, incompatibilities with existing software. The biggest issue would be for software that uses the old template-like macros: such macro invocations can simply be replaced with appropriate typedefs.

  • Made the conversion interface more complete and uniform. Also, using template notation, one can and should now write conv<ZZ>(a) instead of to_ZZ(a) (for backward compatibility, all the old names to_XXX are still there, but many new conversions are not available under these old names).

    There are many new conversions provided. Moreover, whenever there is a conversion from a ring R to a ring S, there is a corresponding, coefficiet-wise conversion from the polynomial ring R[X] to the polynomial ring S[X].

    In addition, using the template mechanism, there are generic conversions for vectors and matrices. For example, if there is a conversion from S to T, then there is automatically a corresponding component-wise conversion from Vec<S> to Vec<T>.

  • Introduced a more general mechanism for accessing GF2's in packed structures via indexing (see the class ref_GF2 in the GF2 module).

  • Employed ideas from David Harvey to make the single-precision FFT faster (about twice as fast in many cases). This speeds up many higher-level operations. See: Faster arithmetic for number-theoretic transforms. J. Symb. Comp. 60 (2014) 113-119.

  • Fixed all known bugs.


2009.08.14: Changes between NTL 5.5.1 and 5.5.2

  • New routines MulAddTo and MulSubFrom for computing x += a*b and x -= a*b, where x and a are ZZ's and b is a ZZ or a long. In the case where b is a long, this may be much faster than writing mul(t, a, b); add(x, x, t). See ZZ.txt for details. These new routines are used in a number of places in NTL to get faster algorithms (for example, the LLL routine).
  • Fixed a relatively benign indexing bug in GF2EX discovered by Berend-Benjamin Tams using the valgrind tool.


2009.05.05: Changes between NTL 5.5 and 5.5.1

  • If using GMP (via either NTL_GMP_LIP or NTL_GMP_HACK), then the new version (4.3.0) of GMP implements the XGCD functionality differently, so that the coefficients do not always agree with those returned by the classical extended Euclidean algorithm. This version of NTL corrects the coefficients, so that the "classical" coefficients are always produced, regardless of GMP's implementation. This version of NTL also works around a bug in GMP 4.3.0's XGCD code (although that bug should be fixed in GMP 4.3.1).
  • The configure script has been slightly modified: there is a new configuration variable DEF_PREFIX, whose value can be used to set PREFIX, GMP_PREFIX, and GF2X_PREFIX in one stroke. Also, the (somewhat esoteric) configure variables GMP_LIBDIR, GMP_INCDIR, GF2X_LIBDIR, and GF2X_INCDIR have slightly different meanings now.


2009.04.08: Changes between NTL 5.4.2 and 5.5

  • Added the ability to generate a shared library (with help from Tim Abbott). Details.
  • Fixed some standardization issues (with help from Tim Abbot): default location of installed documentation files now conforms to standards; use of EOF now conforms to standards.
  • Added a callback mechanism to NTL's error reporting function. See ErrorCallback in tools.txt.
  • Added support for the gf2x library for speeding up arithmetic in GF2X (with help from Emmanuel Thomé). Details.
  • In conjuction with the above, I also changed the GF2X so that it works better with very large polynomials: large blocks of memory are released, recursive HalfGCD algorithms are used for large polynomials.
  • Fixed a bug in void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F) (reported by Luca De Feo).
  • Fixed a performance issue in various versions of SetCoeff (reported by Luca De Feo).
  • Fixed the declaration of mat_zz_p transpose(const mat_zz_p& a) (reported by Benoit Lacelle).


2008.03.05: Changes between NTL 5.4.1 and 5.4.2

  • Fixed a bug in the sub(ZZ_pEX, ZZ_pE, ZZ_pEX) and sub(zz_pEX, zz_pE, zz_pEX) routines (reported by Charanjit Jutla). Under certain circumstances, these could outout wrong answers.


2007.05.09: Changes between NTL 5.4 and 5.4.1

  • Fixed rounding bug in expm1 (reported by Paul Zimmermann).
  • Fixed memory leak in several LLL routines (reported by Friedrich Bahr).
  • Fixed infinite loop in several LLL routines (this only occurred on machines, like x86, with double rounding).
  • Improved GF2X timing tests (suggested by Paul Zimmermann).


2005.03.24: Changes between NTL 5.3.2 and 5.4

  • By default, NTL now compiles in ISO mode (using namespaces, etc.). You can always revert to traditional mode by unsetting the flag NTL_STD_CXX (either pass NTL_STD_CXX=off to the configure script, or manually edit the config.h file).

  • Some bug fixes:
    • The sqrt and log1p routines for the RR class would produce incorrectly rounded results in certain circumstances (although this only affected the relative error of the result very marginally).
    • The SqrRootPrec routine for the RR class could not be called, because it was defined incorrectly.

    Thanks to Paul Zimmermann for finding (and fixing) these bugs! Paul has also validated NTL's RR class by cross-checking it with the MPFR library.

  • Some performance enhancements:
    • Added a new MulModPrecon inline function for computing (a * b) % n for single precision numbers, when b and n are fixed for several computations. On some platforms this can be twice as fast or more than the old MulMod2 routine. This indirectly affects a lot of computations that are done via homomorphic imaging (polynomial multiplication over zz_p, ZZ_p, and ZZ, matrix computations over zz_p and ZZ).
    • Rewrote the small prime FFT to take advantage of the new MulModPrecon, and to be more cache friendly.
    • Improved the performance of the GF2X multiplication routine. On some platforms, it can be twice as fast as the old one. Thanks (again) to Paul Zimmermann for suggesting some of these improvements and supplying some of the code.

  • Miscellany:
    • Rewrote several of the installation scripts in Perl (the old shell scripts were getting too messy to maintain). However, the syntax for all of the command-line interfaces remains identical.


2004.05.21: Changes between NTL 5.3.1 and 5.3.2

  • Some bug fixes.

  • Re-wrote SqrRootMod to make it run faster.


2002.12.17: Changes between NTL 5.3 and 5.3.1

  • Fixed a bug affecting the BuildIrred routines for ZZ_pEX and zz_pEX.


2002.07.05: Changes between NTL 5.2 and 5.3

  • Minimized and isolated constructs that do not adhere to C/C++ standards, and added flags NTL_CLEAN_INT and NTL_CLEAN_PTR which force stricter compliance with these standards [more details].

  • Added functions IsWhiteSpace, CharToIntVal, and IntValToChar to the tools module [more details].

  • Added methods allocated, position1 to generic vector classes [more details].

  • Added method allocated to the class vec_GF2 [more details].

  • Added conversion routines from unsigned int/long to int, long, float, and double [more details].

  • Added routines AddPrec, SubPrec, etc., to the RR module, and declared the practice of directly assigning to the variable RR::prec obsolete [more details].

  • Fixed a number of minor bugs.


2001.07.19: Changes between NTL 5.1a and 5.2

  • Implemented Mark van Hoeij's new algorithm for factorining polynomials with rational coefficients. This new algorithm is much more efficient than the previous algorithm used by NTL, and is the default (one can switch back to the old algorithm with a run-time switch).

    [documentation]

    [performance measurements]

  • Added routines LLL_plus that are just like the all-integer LLL routines, except that they return the exact values of the squared lengths of the Gramm-Schmidt basis vectors. This is useful in implementing van Hoeij's algorithm. [more details].

  • Made a small change to quad_float.c to make it compile under gcc version 3.0 without errors. This is the one place in NTL where I resort to just a little assmebly code (but only on x86/Linux platforms), and wouldn't you know it, this is the one place where gcc 3.0 had problems.

  • Made a small change to the procedure for generating a distribution, so that now all files in the "tar" file comprising the distribution come without any annoyingly excessive access control restrictions.

  • Changes the version numbering scheme so that it is now closer to "standard practice". This is version "5.2". Any small bug fixes to this version will be named "5.2.1", "5.2.2", etc. Also, macros are now defined so that the numerical components of the version number are available to the programmer. [more details].


2001.06.08: Changes between NTL 5.0c and 5.1a

Some minor fixes and additions.

Completely backward compatible.

  • Added a routine LatticeSolve() for finding integer solutions to linear systems of integer equations. [more details]

  • Modified the stragey used by the LLL() and image() routines in the LLL package to deal with linear dependencies. The new strategy guarantees better worst-case bounds on the sizes of intermediate values. I'm not sure if it will have any serious practical impact, though.

  • Added some "partial ISO modes" so that one can use some of the features of Standard C++, even if ones compiler does not yet support all of the features.

  • Bug fix: routine determnant() in mat_GF2.h was not visible to the linker because of a typo in mat_GF2.c.

  • Made a "smarter" script for selecting the GetTime() function. This fixes an installation problem on Cygwin/Windows 95 platforms. I hope it doesn't create more problems than it solves, though.

  • Added some extra documentation for installation under Windows/MS Visual C++. [more details]

  • Changed some names like c_lip.c to c_lip_impl.h. This should avoid some potential installation problems.

  • Throw away first 256-bytes of arc4 streams to improve quality of the pseudo-random number generator. This may change the precise behavior of some programs.

  • Other minor, internal modifications.


2001.02.19: Changes between NTL 5.0b and 5.0c

Fixed a naming problem in the Windows distribution. The Unix distribution is unaffected.


2001.02.19: Changes between NTL 5.0a and 5.0b

Fixed a typo in vec_ulong.c that causes a compile error on some platforms.


2001.02.19: Changes between NTL 4.3a and 5.0a

  • I've now re-structured NTL so that one can use either 'traditional' LIP or GMP as the primary long integer package. Doing this introduced some (minor) backward incompatabilies in the programming interface, so there is also a 'third way' -- you can use GMP as a supplemental long integer package (as in NTL 4.3), getting many (but not all) of the performance benefits of GMP, while maintaining complete backward compatability with the traditional long integer package. This 'third way' is not highly recommended -- it is only intended as a backward compatabilty hack.

    Even if you do not use GMP, you should read about using NTL with GMP so that you can write code that works with either the traditional or GMP long integer packages.

  • Added a ZZ to unsigned long conversion routine. [more details]
  • Added new vector classes vec_ulong (vectors of unsigned longs) and vec_vec_ulong. [more details]
  • Some minor bug fixes: under some unusual circumstances, a memory allocation error could be erroneously raised; I also added a patch that works around a bug in v3.0.1 of GMP.
  • Some internal cleansing, minimizing the use of non-standard constructs.


Changes between NTL 4.2a and 4.3a

This is backward compatible with previous versions.

  • Improved the performance of ZZ_pX arithmetic when using GMP. The GMP version is also more space efficient (the pre-computed tables are much smaller). These improvements are most marked for very large p (several thousand bits).

    The only thing unsatisfactory about this state of affairs is that vis a vis the GMP version, the pure LIP code is asymptotically slower by more than a constant factor, and is is also less space efficient. Perhaps I'll get around to rectifying this imbalance someday. To do this, I need a sub-quadratic division with remainder routine for LIP. At any rate, the differences only become seriously noticible when p has more than a few thousand bits.

  • Some other small adjustments here and there.


Changes between NTL 4.1a and 4.2a

This is backward compatible with previous versions.

  • Hacked the big integer code so that NTL uses GMP (the GNU Multi-Precision library). This is done in such a way as to get most of the benefits of GMP with a reasonable amount of effort, and while maintaining complete backward compatability and minimizing the risk of introducing bugs. Some arithmetic operations on some platforms may execute two to three times faster if using GMP. [more details]
  • Simplified the installation procedure on Unix systems by providing a simple configuration script so that setting various configuration variables can be done without editing the makefile and config.h file. [more details]
  • Added function GenGermainPrime to efficiently generate random Germain primes, i.e., primes p such that 2p+1 is also prime. [more details]
  • Added a function random to generate random quad_floats. [more details]
  • Added an ifdef in tools.h that allows one to suppress the declaration of min and max functions in NTL client programs; these were causing problems when writing 'Windows applications'.
  • Implemented a faster algorithm for initializing the ZZ_p auxilliary data structures.
  • Polished up a few other minor things in the code and documentation.


Changes between NTL 4.0a and 4.1a

This is backward compatible with previous versions.

  • Made some changes that should make NTL compile smoothly using any variation of the C++ language between traditional and ISO Standard. These changes do not affect the documented NTL interface or the behaviour of NTL.
  • Added a flag NTL_STD_CXX in the config.h file. Setting this flag causes all of NTL to be "wrapped" in namespace NTL, and that part of the standard library used by NTL is "wrapped" in namespace std. This should greatly help with the namespace pollution problem.


Changes between NTL 3.9b and 4.0a

This is backward compatible with previous version.

  • Attached the GNU General Public License to NTL.
  • Fixed two bugs:
    • one in ReconstructRational which resulted in a crash on some inputs;
    • one in exp(RR) (and by implication in pow(RR,RR)), which led to wrong answers on 64-bit machines when computing exp(x) for x > 2^53.
  • Increased some inconvenient limiting bounds, including a restriction on the FFT.


Changes between NTL 3.9a and 3.9b

This is a minor revision of 3.9a.

  • Improved time and space efficiency of the HNF routine (see HNF.txt). The old version was based on the description in Henri Cohen's book, which was not really properly optimized.


Changes between NTL 3.8b and 3.9a

This is backward compatible with previous versions.

  • Modified the installation script somewhat, adding a configuration wizard that sets the flags in config.h "automagically". This works for the Unix version only.
  • Improved the xdouble input/output and ascii to xdouble conversion. The old version could be a bit flaky when reading/writing very large numbers. The new I/O routines also attain better accuracy.
  • Improved conversion routines between xdouble and ZZ/RR.
  • Improved the RR output routine. The new version should be more accurate and also completely platform independent.
  • Added the following routines to the RR package:
       {Trunc,Floor,Ceil,Round}ToZZ, round
       RoundToPrecision, MakeRR
       random
    
    See RR.txt for details.
  • Improved the accuracy of quad_float input/output, and the accuracy of conversion between quad_float and RR.
  • Made the timing function somewhat more robust.
  • Hacked the Unix installation script so that it works more smoothly with Cygnus tools under Windows.
  • Fixed a few other, small problems.


Changes between NTL 3.8a and 3.8b

This is a minor revision of 3.8a.

  • Fixed a bug, a memory leak in routine gauss for mat_ZZ_pE and mat_zz_pE.
  • Fixed a minor problem in config.h.
  • Tightened up some size checks, so that now some nice "size invariants" are guaranteed, e.g., for a ZZ n,

       NumBits(NumBits(n)) <= NTL_BITS_PER_LONG-4

    Similarly for the type GF2X. Of course, on most platforms, one will run out of memory before these bounds are exceeded, but they are nevertheless convenient.


Changes between NTL 3.7a and 3.8a

This is backward compatible with previous versions.

  • Added conversion routines from unsigned int and unsigned long to ZZ, RR, xdouble, and quad_float.
  • Added routines GF2XFromBytes and BytesFromGF2X for conversion between byte vectors and polynomials over GF(2), along with routines NumBits and NumBytes for such polynomials. See GF2X.txt for details.
  • Added a hack in the ZZX factorizer to exploit polynomials of the form g(x^k). This can be disabled by setting the variable ZZXFac_PowerHack to zero. See ZZXFactoring.txt for details.
  • Improved the hensel system solver solve1. See mat_ZZ.txt for details.
  • Changed documentation for RationalReconstruction to reflect the Wang, Guy, Davenport bounds. See ZZ.txt for details.
  • Improved the routine GenPrime a bit.
  • Some other small tweaks here and there. No real bug fixes.
  • Polished the documentation a bit, adding more examples.


Changes between NTL 3.6b and 3.7a

This is backward compatible with previous versions.

  • Added a "rational reconstruction" routine. See the routine ReconstructRational in ZZ.txt.
  • Added another routine for solving linear systems over ZZ that is based on Hensel lifting, rather than Chinese Remaindering. It can be significantly faster in some cases. See the routine solve1 in mat_ZZ.txt).
  • Some performace tuning, especially CRT and polynomial interpolation code.
  • Various documentation corrections.
  • Added more "overflow checks" here and there to ensure programs crash gracefully when certain things get too big.
  • Fixed a "benign" bug (i.e., it would never get triggered on any of today's machines).
  • Removed references to <malloc.h>, which were unnecessary, non-standard, and caused problems on some platforms.


Changes between NTL 3.6a and 3.6b

Bug fixes.


Changes between NTL 3.5a and 3.6a

This version is backward compatible with 3.5a.

  • A few small bug fixes and performance enhancements.
  • Changed to the ZZX factoring routines that in some cases yield dramatic performance improvements (more details).


Changes between NTL 3.1b and 3.5a

Please note. This version is NOT completely backward compatible.

Summary of changes:

  • Improved performance of the "all integer" LLL routine.
  • Put in a better pseudo-random number generator, and added ZZ/byte array conversions.
  • Improved performance of primality test, and added a more convenient routine GenPrime.
  • Overloaded NTL's vector placement "new" operator in a different way to avoid conflicts with standard C++ library.
  • Renamed many macros.
  • Renamed header files.
  • Made some changes to the packaging the installation procedure.

Renamed Macros. I renamed many macros defined in NTL header files.

The reason is that I want to minimize namespace pollution. Someday, NTL will be wrapped in a namespace, and when that happens the only remaining namespace pollution problems will be caused by macros. Eliminating all macros from NTL is not feasible. Instead, all NTL defined macros now begin with the prefix "NTL_", which reduces the namespace pollution to an ecceptable level. You will probably not be affected by this, unless you do some low level hacking using a macro like ZZ_NBITS (now called NTL_NBITS), or unless you create your own NTL vectors using a macro like ntl_vector_decl (now called NTL_vector_decl).

For a complete list of affected names, see names.txt.

Adapting to this name change should be painless, as there is a program to translate source files from the old naming convention to the new. The file "newnames.c", can be compiled as either a C or C++ program. The program is a "filter" that copies its input to its output, replacing all the old macro names by the new macro names.

In the WinNTL distribibution, "newnames.c" is called "newnames.cpp" and is located in the directory "newnames".

Renamed header files. The names of header files themeselves pollute another (extra-linguitsic) namespace. To alleviate this problem, the header files have been renamed. Instead of

   #include "foo.h"

one now should write

   #include <NTL/foo.h>

The only exceptions are the old header files "ntl_vector.h", "ntl_matrix.h", and "ntl_pair.h", which are now called <NTL/vector.h>, <NTL/matrix.h>, and <NTL/pair.h>.

Installation procedure. Now all NTL flags like NTL_LONG_LONG, NTL_AVOID_FLOAT, etc., can now be set by editing the special file "include/NTL/config.h". See details in that file. The reason for this change is that this allows all of these settings to be made when NTL is configured and built. Clients of NTL will then automatically use consistent settings. One should not set these flags on the compiler command line as previously.

Pentium/Linux people should no longer have to worry about the NTL_X86_FIX flag. NTL now psychically deduces the "right thing to do", although if its psychic abilities fail, you can override it with flags in "include/NTL/config.h".

The "packaging" in the Unix distribution is slightly different, but hopefully nicer. Among other things, the tar file now unpacks into a sub-directory of the current directory. See the unix installation section for more details. The Windows zip file now also unpacks into sub-directory.

My apologies. Although these changes are minor, they will cause some NTL users some inconvenience. I apologize for this. I really, really hope there are no more changes like this (see my roadmap of NTL's future).


Changes between NTL 3.1a and 3.1b

Defined functions div(GF2X,GF2X,GF2) and div(GF2X,GF2X,long), which had not been defined in earlier versions. Affected file: GF2X.c. Most programs never use this, and most linkers do not complain if these are missing (but some do).


Changes between NTL 3.0f and 3.1a

This version is backward compatible with previous versions.

  • Added floating point LLL routines based on Givens rotations, instead of classical Gramm-Schmidt orthogonalization. This is a more stable, but somewhat slower, method. See LLL.txt for details.
  • Added support for irreducible trinomials and pentanomials over GF(2). The GF2XModulus routines, and by extension, the GF2E routines, now exploit moduli of this special form. The new routine BuildSparseIrred in GF2XFactoring builds irreducibles of this form.
  • Also implemented a faster modular inversion routine for GF2X, and improved the performance of ZZ_pX multiplication for small degree polynomials.


Changes between NTL 3.0e and 3.0f

  • Fixed a bug (another one) affecting routines
       RandomBits, RandomBits_ZZ
    
    in module ZZ. Affected source file: lip.c.
  • Bug fix and performance tweak in ZZX factorizer. Affected source file: ZZXFactoring.c.


Changes between NTL 3.0 and 3.0e

  • Fixed a bug affecting routines
       RandomBits, RandomBits_ZZ, RandomBits_long
    
    in module ZZ. The only source files that are affected and require re-compilation are
       ZZ.c, lip.c
    
  • Note about names: 3.0a-c were "pre-releases", which makes the "first release" 3.0d, and hence this bug fix 3.0e.


Changes between NTL 2.0 and 3.0

  • Added functionality:

    • Added classes vec_GF2 and mat_GF2 for fast linear algebra over GF(2).
    • Added classes ZZ_pE, ZZ_pEX, zz_pE, zz_pEX, supporting polynomial arithmetic over extension rings/fields over prime fields.
    • Added John Abbott's pruning heuristic to the ZZX factoring routine.
    • Speeded up multiplication in zz_pX for small p (this also helps the ZZX factoring routine).
    • Added some some transcendental functions (e.g., exp, log, pi) to RR.
    • Added verbose mode and pruning to the XD and RR variants of LLL.

  • Improved programming interface: with this version, I've taken an the opportunity to give the programming interface a "professional facelift". In previous releases, I've tried to maintain backward compatability as much as possible, but to make the badly needed improvements to the interface that I've made with this release, this was not possible.

    NTL 3.0 is not backward compatable with NTL 2.0.

    I apologize to NTL users for this, but it is a bit of painful medicine that should only be necessary to take just this one time (but then as a C++ programmer, you must already be used to suffering ;-). Just about all of the incompatabilities are detectable by the compiler. See below for a detailed list of the changes and some tips on making the transition.

    The new interface is much more enjoyable to work with, and I don't foresee any changes to the interace in the future. Here is a broad overview of the changes:

    • Added functional/operator notation consistently throughout NTL, making it possible to write much more concise and readable code.
    • Got rid of automatic type conversions: these cause just too many problems. But I've overloaded all of the basic arithmetic operators and procedures so as to emulate a natural kind of "type promotion" logic. With these promotions, along with a full compliment of conversion functions, one hardly misses the automatic conversions.
    • Got rid of the macros
         vector(T), matrix(T), pair(T),
      
      which were causing too many name space problems.
    • Made assignment operators have the "correct" return type.
    • Introduced a more powerful and flexible mechanism for modulus changing.
    • Cleaned up numerous other minor problems.

Compatibility

Here is a detailed list of the changes to the programming interface.

  • The names of the classes
       BB, BB_p, BB_pX
    
    have been changed to
       GF2X, GF2E, GF2EX
    
  • There is also a class GF2 to represent GF(2). Many of the functions relating to BB, BB_p, BB_pX had argument and return-value types of type long that are now of the more appropriate type GF2. This change was needed so that the interface would be consistent with that of the new classes
       ZZ_pE, ZZ_pEX, zz_pE, zz_pEX.
    
  • The explicit conversion operator from GF2X (the new BB) to GF2EX (the new BB_pX) has different semantics: it now performs a coefficient lift, instead of creating a constant polynomial.
  • The conversion operator "<<" has been retired. Now instead of

       x << a; 

    one writes

       conv(x, a);

    Operator "<<" is now used for shift operations.

  • Every conversion routine now has a corresponding functional version which has the name to_T, where T is the result type. These new names replace old names that were less consistent. So instead of

       x = Long(a);

    one writes

       x = to_long(a);

  • The names of the routines
       ZZ_pInit, zz_pInit, zz_pFFTInit, GF2EInit
    
    have been changed to
       zz_p::init, zz_p::init, zz_p::FFTInit, GF2E::init
    
  • The names of the routines
       and, or, xor 
    
    for class ZZ have changed to
       bit_and, bit_or, bit_xor, 
    
    because the new C++ standard defines these as reserved words.
  • The function LowBits for ZZ is now called trunc.
  • Polynomial inversion mod X^n has changed from inv to InvTrunc.
  • Modular trace, norm, minimum polynomial and characteristic polynomial have changed from
       trace, norm, MinPoly, IrredPoly, CharPoly
    
    to
       TraceMod, NormMod, MinPolyMod, IrredPolyMod, CharPolyMod
    
  • For the class ZZX, the functions
       DivRem, div, rem, /, %, /=, %=
    
    have new semantics when dividing by non-monic polynomials. The old semantics are provided by new routines
       PseudoDivRem, PseudoDiv, PseudoRem.
    
  • The UpdateMap routines have slightly different semantics: in versions < 3.0, the output always had length n; now high-order zeroes are stripped.
  • The classes ZZ_pBak, zz_pBak, etc., have just slightly different semantics; I can't imagine any reasonable program detecting a difference.
  • The assignment operator and copy constructor for the class RR have different semantics: they now produce exact copies, instead of rounding to current precision.
  • All of the NTL compiler flags now start with NTL_ to avoid name space problems.
  • All of the files "zz_p.h", vec_zz_p.h", etc., have been eliminated. Use instead the names "lzz_p.h", "vec_lzz_p.h", etc.

Tips on making the transition

  • Apply this sed script to make most of the necessary syntactic changes.
  • Re-compile old NTL programs with the flag
       -DNTL_TRANSITION
    
    See flags.txt for details on how this will help your compiler detect remaining incompatabilities. In particular, any uses of operator << in its old role as a conversion operator will cause the compiler to raise an error. You can then convert all of these to the new notation.


Changes between NTL 1.7 and 2.0

  • Implementation of classes BB (polynomials over GF(2)) and BB_pX (polynomials over GF(2^n)).
  • A more consistent and natural interface, including arithmetic operators and a disciplined use of automatic conversion. So now one can write

       x = a * b + c;

    instead of

       mul(x, a, b);
       add(x, x, c);

    as one must in older versions of NTL. The operator notation leads to somewhat less efficient code, and one can always use the old notation in situations where efficiency is critical. Despite the new programming interface, care has been taken to ensure backward compitability; pre-existing programs that use NTL should still work.

  • Windows port.
  • Added compile-time flag that allows one to exploit "long long" data type if it exists (this especially helps on Pentium/Linux platforms).
  • Added compile-time flag to get better quad_float code on Pentium/Linux platforms.
  • A few bug fixes and performance tuning.


Changes between NTL 1.5 and NTL 1.7

  • Incorporation of Keith Briggs' quadratic precision package.
  • Much faster and more robust lattice basis reduction, including Schnorr-Horner "volume heuristic" for Block Korkin Zolotarev reductions, and a new quadratic precision LLL variant that is much more robust.
  • A few bug fixes.


Changes between NTL 1.0 and NTL 1.5

  • Implementation of Schnorr-Euchner algorithms for lattice basis reduction, including deep insertions and block Korkin Zolotarev reduction. These are significantly faster than the LLL algorithm in NTL 1.0.
  • Implementation of arbitrary-precision floating point.
  • Implementation of double precision with extended exponent range, which is useful for lattice basis reduction when the coefficients are large.
  • Faster polynomial multiplication over the integers, incorporating the Schoenhagge-Strassen method.
  • Compilation flags that increase performance on machines with poor floating-point performance.
  • Sundry performance tuning and a few bug fixes.
[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-modules.html0000644417616742025610000004521114064716023020253 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Summary of NTL's Main Modules
[Previous] [Up] [Next]

A Tour of NTL: Summary of NTL's Main Modules


NTL consists of a number of software modules. Generally speaking, for each module foo, there is

  • a header file <NTL/foo.h>, found in subdirectory include,
  • a documentation file foo.txt, found in subdirectory doc, and
  • a source file foo.cpp, found in subdirectory src.

Note that all of the header files for NTL modules include the header file <NTL/tools.h>, and by default, this header file includes the standard headers

  • <cstdlib>,
  • <cmath>, and
  • <iostream>.
Moreover, the standard library is wrapped in namespace std and NTL is wrapped in namespace NTL.

The documentation file takes the form of a header file, but stripped of implementation details and declarations of some of the more esoteric routines and data structures, and it contains more complete and usually clearer documentation than in the header file. Also, note that the documentation files do not explicitly mention anything about namespaces std and NTL.

There is a plethora of conversion routines. These are not documented in any of the individual documentation files, but rather, they are all briefly summarized in conversions.txt.

The following is a summary of the main NTL modules. The corresponding documentation file can be obtained by clicking on the module name. Note that the links below will take you to a "pretty printed" version of the correspinding .txt file.

BasicThreadPool class BasicThreadPool: a simple thread pool; plus additional thread boosting features

GF2 class GF2: integers mod 2

GF2X class GF2X: polynomials over GF(2) (much more efficient than using zz_pX with p=2); includes routines for GCDs and minimal polynomials

GF2XFactoring routines for factoring polynomials over GF(2); also includes routines for testing for and constructing irreducible polynomials

GF2XVec class GF2XVec: fixed-length vectors of fixed-length GF2Xs; less flexible, but more efficient than vec_GF2X

GF2E class GF2E: polynomial extension field/ring over GF(2), implemented as GF(2)[X]/(P).

GF2EX class GF2EX class GF2EX: polynomials over GF2E; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

GF2EXFactoring routines for factoring polynomials over GF2E; also includes routines for testing for and constructing irreducible polynomials

HNF routines for computing the Hermite Normal Form of a lattice

Lazy Support for thread-safe lazy initialization of objects

LazyTable Support for thread-safe lazy initialization of tables

LLL routines for performing lattice basis reduction, including very fast and robust implementations of the Schnorr-Euchner LLL and Block Korkin Zolotarev reduction algorithm, as well as an integer-only reduction algorithm. Also, there are routines here for computing the kernel and image of an integer matrix, as well as finding integer solutions to linear systems of equations over the integers.

RR class RR: arbitrary-precision floating point numbers.

SmartPtr template classes SmartPtr, UniquePtr, and a few other useful classes for managing pointers.

ZZ class ZZ: arbitrary length integers; includes routines for GCDs, Jacobi symbols, modular arithmetic, and primality testing; also includes small prime generation routines and in-line routines for single-precision modular arithmetic

ZZ_limbs Low-level routines for accessing the "limbs" of a ZZ.

ZZVec class ZZVec: fixed-length vectors of fixed-length ZZs; less flexible, but more efficient than vec_ZZ

ZZX class ZZX: polynomials over ZZ; includes routines for GCDs, minimal and characteristic polynomials, norms and traces

ZZXFactoring routines for factoring univariate polynomials over ZZ

ZZ_p class ZZ_p: integers mod p

ZZ_pE class ZZ_pE: ring/field extension of ZZ_p

ZZ_pEX class ZZ_pEX: polynomials over ZZ_pE; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

ZZ_pEXFactoring routines for factoring polynomials over ZZ_pE; also includes routines for testing for and constructing irreducible polynomials

ZZ_pX class ZZ_pX: polynomials over ZZ_p; includes routines for modular polynomials arithmetic, modular composition, minimal and characteristic polynomials, and interpolation.

ZZ_pXFactoring routines for factoring polynomials over ZZ_p; also includes routines for testing for and constructing irreducible polynomials

lzz_p class zz_p: integers mod p, where p is single-precision

lzz_pE class zz_pE: ring/field extension of zz_p

lzz_pEX class zz_pEX: polynomials over zz_pE; provides the same functionality as class ZZ_pEX, but for single-precision p

lzz_pEXFactoring routines for factoring polynomials over zz_pE; provides the same functionality as class ZZ_pEX, but for single-precision p

lzz_pX class zz_pX: polynomials over zz_p; provides the same functionality as class ZZ_pX, but for single-precision p

lzz_pXFactoring routines for factoring polynomials over zz_p; provides the same functionality as class ZZ_pX, but for single-precision p

matrix template class for dynamic-size 2-dimensional arrays

mat_GF2 class mat_GF2: matrices over GF(2); includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_GF2E class mat_GF2E: matrices over GF2E; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_RR class mat_RR: matrices over RR; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, and solving nonsingular systems of linear equations.

mat_ZZ class mat_ZZ: matrices over ZZ; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, and solving nonsingular systems of linear equations. See also the LLL module for additional routines.

mat_ZZ_p class mat_ZZ_p: matrices over ZZ_p; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_ZZ_pE class mat_ZZ_pE: matrices over ZZ_pE; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_lzz_p class mat_zz_p: matrices over zz_p; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_lzz_pE class mat_zz_pE: matrices over zz_pE; includes basic matrix arithmetic operations, including determinant calculation, matrix inversion, solving nonsingular systems of linear equations, and Gaussian elimination

mat_poly_ZZ routine for computing the characteristic polynomial of a mat_ZZ

mat_poly_ZZ_p routine for computing the characteristic polynomial of a mat_ZZ_p

mat_poly_lzz_p routine for computing the characteristic polynomial of a mat_zz_p

pair template class for pairs

quad_float class quad_float: quadruple-precision floating point numbers.

tools some basic types and utility routines, including the timing function GetTime(), and several overloaded versions of min() and max()

vector template class for dynamic-size vectors

vec_GF2 class vec_GF2: vectors over GF(2), with arithmetic

vec_GF2E class vec_GF2E: vectors over GF2E, with arithmetic

vec_RR class vec_RR: vectors over RR, with arithmetic

vec_ZZ class vec_ZZ: vectors over ZZ, with arithmetic

vec_ZZ_p class vec_ZZ_p: vectors over ZZ_p, with arithmetic

vec_ZZ_pE class vec_ZZ_pE: vectors over ZZ_pE, with arithmetic

vec_lzz_p class vec_zz_p: vectors over zz_p, with arithmetic

vec_lzz_pE class vec_zz_pE: vectors over zz_pE, with arithmetic

version macros defining the NTL version number

xdouble class xdouble: double-precision floating point numbers with extended exponent range.

Some other types

In addition to the above, other generic vectors are declared, not explicitly documented elsewhere:

  • vec_GF2XVec
  • vec_ZZVec
  • vec_double
  • vec_long
  • vec_quad_float
  • vec_ulong
  • vec_vec_GF2
  • vec_vec_GF2E
  • vec_vec_RR
  • vec_vec_ZZ
  • vec_vec_ZZ_p
  • vec_vec_ZZ_pE
  • vec_vec_long
  • vec_vec_lzz_p
  • vec_vec_lzz_pE
  • vec_vec_ulong
  • vec_xdouble

These decalarations are found in ".h" files with corresponding names. These header files simply provide typedefs for the corresponding template types, mainly for backward compatibility, e.g., vec_double is a typedef for Vec<double>, and vec_vec_RR is a typedef for Vec< Vec<RR> >. No additional functionality is provided.

All of the header files for polynomial classes ZZ_pX, ZZX, etc., declare typedefs for the corresponding vectors of polynomials vec_ZZ_pX, vec_ZZX, etc.

There are also a number of generic pair classes defined, not explicitly documented elsewhere:

  • pair_GF2EX_long
  • pair_GF2X_long
  • pair_ZZX_long
  • pair_ZZ_pEX_long
  • pair_ZZ_pX_long
  • pair_lzz_pEX_long
  • pair_lzz_pX_long

These decalarations are found in ".h" files with corresponding names. Again, these files mainly exist for backward compatibilty, and provide typedefs for the corresponding template types, e.g., pair_GF2EX_long is a typedef for Pair<GF2EX,long>. These files also give typedefs for the corresponding vector types, e.g., vec_pair_GF2EX_long is a typedef for Vec< Pair<GF2EX,long> >. No additional functionality is provided.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-unix.html0000644417616742025610000005337214064716023017575 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Obtaining and Installing NTL for UNIX
[Previous] [Up] [Next]

A Tour of NTL: Obtaining and Installing NTL for UNIX


This procedure should work on most Unix or Unix-like platorms (including Mac OS, and Windows with MinGW or Cygwin tools).

To obtain the source code and documentation for NTL, download ntl-xxx.tar.gz, placing it a directory, and then, working in this directory, do the following. Here, "xxx" denotes the current version number.

   % gunzip ntl-xxx.tar.gz
   % tar xf ntl-xxx.tar
   % cd ntl-xxx/src
   % ./configure 
   % make
   % make check
   % sudo make install
This will build, test, and install NTL in /usr/local. For this to work, GMP must already be installed (most Unix distributions already come with GMP installed, but see this page for more details). If you really do not want to use GMP, you can pass the option NTL_GMP_LIP=off to configure; however, NTL will run significantly faster with GMP, so this is strongly discouraged.

After installation, you will find the NTL header files in /usr/local/include/NTL and the compiled binary in /usr/local/lib/libntl.a (this is a static library -- if you want a shared library, see below). Documentation is in /usr/local/share/doc, with the main entry-point at /usr/local/share/doc/tour.html.

If you want very high-performance for polynomial arithmetic over GF(2), you may want to consider using the gf2x library. To do this, gf2x must already be installed. In addition, you should invoke configure with the option NTL_GF2X_LIB=on. This page provides more details.

If you want to install NTL somewhere besides /usr/local, pass the option PREFIX=/path/to/install/ntl to configure. If you do this, you may not need to run make install using sudo. If GMP is installed somewhere besides /usr/local, pass the optopn GMP_PREFIX=/path/to/gmp to configure. You can also pass GF2X_PREFIX=/path/to/gf2x to configure, if gf2x is installed somewhere besides /usr/local.

As a shorthand, you pass the option DEF_PREFIX=/path/to/all/software, which will override the default for PREFIX, GMP_PREFIX, and GF2X_PREFIX.

Now suppose you want to compile a program that uses NTL. Suppose you are working in some arbitrary directory and foo.cpp is your program. Assume that you have installed NTL in /usr/local as above. The following should work:

   % g++ -g -O2 -std=c++11 -pthread -march=native foo.cpp -o foo -lntl -lgmp -lm

NOTES:

  1. By default, NTL is built in C++11 mode, and you will need to ensure that your compiler configured to accept C++11. This can usually be acomplished by passing -std=c++11 to the compiler. Newer versions (6.1 or later) of GCC compile in C++14 mode by default, so this may not be not necessary (or even desirable). This same option can be passed to other GCC-like compilers, such as CLANG and Intel's ICC compiler.
  2. By default, NTL is built with multithreading enabled, and for this reason, you may need to pass the -pthread option to GCC. This same option can be passed to other GCC-like compilers, such as CLANG and Intel's ICC compiler.
  3. The -march=native option is usually a good idea to get best performance for code targeted to a specific x86 architecture. This same option can be passed to other compilers, like CLANG and Intel's ICC compiler.
  4. You can look in the file /usr/local/include/NTL/ConfigLog.h to see what options (in addition to -g -O2) were chosen by NTL's configuration script. Look for a line that looks like this:
       CXXAUTOFLAGS=" -std=c++11 -pthread -march=native"
    
  5. If you build NTL with gf2x, just add the option -lgf2x to the above, right after -lgmp. Again, if NTL is built as a shared library, this may not be necessary.

If you are working in the NTL src directory itself, you can just run:

   % make foo
to compile a program foo.cpp, as above.

More Details

What follows is a more detailed description of the installation process.

Step 1. Extract the source files by executing:

   % gunzip ntl-xxx.tar.gz
   % tar xvf ntl-xxx.tar
On most systems, the following shortcut works:
   % tar xzvf ntl-xxx.tar.gz

Note that this will unpack everything into a sub-directory ntl-xxx, creating this directory if necessary. Next:

   % cd ntl-xxx
   % ls
You should see a file "README", and directories "include", "doc", and "src". The directory "doc" contains all the documentation. The file "doc/tour.html" contains a copy of the on-line documentation. The directory "include" contains all the header files within a subdirectory "include/NTL". The directory "src" contains everything else. Go there now:
   % cd src

Step 2. Run the configuration script.

Execute the command

   % ./configure [ variable=value ]...
This configure script generates the file "makefile" and the file "../include/NTL/config.h", based upon the values assigned to the variables on the command line.

Here are the most important variables, and their default values.


CXX=g++              # The C++ compiler

CXXFLAGS=-g -O2      # C++ complilation flags

NATIVE=on            # Compiles code targeted to the current hardware (see below)
TUNE=generic         # performance-tuning switch (see below)
(or x86 or linux-s390x)

DEF_PREFIX=/usr/local# Default software directory

PREFIX=$(DEF_PREFIX) # Directory in which to install NTL library components
SHARED=off           # Generate a shared library (as well as static -- see below)

NTL_THREADS=on       # compile in thread-safe mode (see below)
NTL_THREAD_BOOST=on  # compile with thread boosting enabled (see below)
NTL_EXCEPTIONS=off   # compile with exceptions enabled (see below)

NTL_GMP_LIP=on       # Switch to enable the use of GMP as primary 
                     #   long integer package

GMP_PREFIX=$(DEF_PREFIX) # Directory in which GMP components are installed

NTL_GF2X_LIB=off     # Switch to enable the use of the gf2x package
                     #   for faster arithmetic GF(2)[X]

GF2X_PREFIX=$(DEF_PREFIX) # Directory in which gf2x components are installed

NTL_STD_CXX11=on     # Build assuming C++11 features

NTL_SAFE_VECTORS=on  # build in "safe vector" mode 


Examples.

  • If you are happy with all the default values, run:
       % ./configure
    

  • If your C++ compiler is called icpc (i.e., the Intel C++ compiler), run:
       % ./configure CXX=icpc
    

  • If you want to use, say, the options -g, -O2, and -march=core-avx2, compiling C++, run:
       % ./configure "CXXFLAGS=-g -O2 -march=core-avx2" 
    
    Note that the conguration script will detect that you are passing an -march=XXX option through CXXFLAGS, and will therefore surpress the -march=native option.

  • If you don't want thread safety, run:
       % ./configure NTL_THREADS=off
    
    This will also turn off thread boosting (see below), and you won't have to pass the option -pthread through to compile your programs.

  • If GMP was installed in $HOME/sw, run:
       % ./configure GMP_PREFIX=$HOME/sw
    
    Go here for complete details.

  • If gf2x is installed in a standard system directory, and you want to use it to obtain better performance for polynomial arithemtic over GF(2), run:
       % ./configure NTL_GF2X_LIB=on
    
    If gf2x was installed in $HOME/sw, run:
       % ./configure NTL_GF2X_LIB=on GF2X_PREFIX=$HOME/sw
    
    Go here for complete details.

  • If you want to install NTL in the directory $HOME/sw, run:
       % ./configure PREFIX=$HOME/sw
    

Some magic. The special makefile variable CXXAUTOFLAGS is automagically set by the configuration script. These are C++ compiler flags that are selected depending on the choice of other configuration options. This is geared towards GCC, but should work pretty well for other compilers, such as CLANG and ICC. The configuration script always tests that these flags actually work, and prints out the flags that it chooses. If you explicitly set CXXAUTOFLAGS when invoking the configuration script, then it will not change that value.

To set CXXAUTOFLAGS and for other checks, the configure script actually needs to run make. If you wish to use a non-standard make program for this purpose, say gmake, set MAKE_PROG=gmake.

Going native. If NATIVE=on (the default), then using the CXXAUTOFLAGS mechanism, the flag -march=native gets passed to the compiler (assuming the compiler accepts that flag). Some users may choose to override this mechanism by setting NATIVE=off, since -march=native can cause trouble in some environments. The default, however, is NATIVE=on, because otherwise most users will end up not benefiting from important optimizations. If you do opt to set NATIVE=off, please consider adding more specific flags to CXXFLAGS, such as

  • -mavx to enable AVX instructions,
  • -mavx2 -mfma to enable AVX2 and FMA instructions,
  • -mpclmul to enable the PCLMUL instruction.
These are by far the most important instructions that NTL currently exploits, so they should be enabled if at all possible. Alternatively, you could add -march=XXX to CXXFLAGS to enable instructions for a specific CPU type (e.g., XXX=core-avx2 works for Haswell CPUs). Doing so will automatically set NATIVE=off.

The question of "fat builds" for NTL has occasionally come up. While that is not possible at the moment, it should still be possible to build different versions of NTL targeted for different micro-architectures. NTL's include files generally do not depend on the micro-architecture, so it should be possible to compile client code against a single set of header files, and then dynamically link against the approprate version of the library.

Tuning options. If TUNE=auto, then make will run a performance-tuning "wizard" to set a number of fine-grained performance options. This is highly recommended, as it will choose options that are best suited to your particular hardware and compiler; however, it can be a bit time consuming. Alternatively, you can set TUNE to one of the following values.

  • generic: chooses options that should be OK for most platforms
  • x86: chooses options that should be well suited for most x86 platforms
  • linux-s390x: chooses options that should be well suited for Linux on IBM Z platforms from z15 onward.
More choices may be added in the future. Right now, the default is
  • x86, if configure detects that is is running on an x86 platform,
  • linux-s390x, if configure detects that it is running on Linux on an IBM Z platform and the compiler is either gcc or clang, and
  • generic, otherwise.

Esoterica. There are a number of more esoteric configuration variables that can be set. See config.txt for a complete description.

Step 3. Execute make.

Just type:

   % make

The build process after this point is fully automatic. But here is a description of what happens.

  1. The makefile invokes make clobber, which gets rid of just about anything that was created by a previous run of make.
  2. The makefile builds the file "../include/NTL/mach_desc.h", which defines some machine characteristics such as word size and floating-point precision. This is done by compiling and running a C++ program called MakeDesc that figures out these characteristics on its own, and prints some diagnostics to the terminal.

  3. Several scripts are run to obtain more information about your system (e.g., to find a timing function, a "getpid" function, and to detect if things like Intel AVX intrinsics work).

  4. The file "../include/NTL/gmp_aux.h" is generated for use with GMP. If not using GMP, this file is still created, but it is empty.

  5. If necessary, the compatbility of the gf2x library is verified.

  6. If TUNE=auto, the configuration wizard script is run. This script works in a sub-directory, compiling several programs, and performing a number of timing experiments, in order to determine the optimal setting for a number of flags in the file ../include/NTL/config.h. When the script finishes (it may take several minutes), you will be told what the wizard thinks are the best settings, and your config.h file will be automatically updated. Note that any flags you set in Step 2 will be in effect while the wizard runs, and will be retained in the updated config.h file, with the exception of the flags
       NTL_AVOID_BRANCHING NTL_SPMM_ULL NTL_FFT_LAZYMUL NTL_FFT_BIGTAB
       NTL_GF2X_NOINLINE NTL_GF2X_ALTCODE NTL_GF2X_ALTCODE1 
       NTL_TBL_REM NTL_CRT_ALTCODE NTL_CRT_ALTCODE_SMALL
    
    which are set by the wizard.

  7. The makefile will compile all the source files, and then create the library "ntl.a" in the current directory.

After NTL is built.

Executing make check runs a series of timing and test programs. It is a good idea to run this to see if everything really went well. It may take a few minutes.

Executing make install copies a number of files to a directory <prefix> that you specify by passing PREFIX=<prefix> as an argument to configure at configuration time. The default is /usr/local, so either you need root permissions, or you choose a <prefix> for which you have write permission. The files ../include/NTL/* are copied into <prefix>/include/NTL. The file ntl.a is copied to <prefix>/lib/libntl.a. The files ../doc/* are copied into <prefix>/share/doc/NTL.

You can also "fine tune" the installation procedure further. See the configure documentation for details.

To allow for the "staging area" trick that some package managers use, the makefile uses a vatriable DESTDIR that is prepended to PREFIX at installation time. So executing

   % make install DESTDIR=/path/to/staging/area
will install the components into the staging area. Note that DESTDIR is set to empty by default, and is not set by the configure script.

Executing make uninstall undoes make install.

Executing make clobber essentially removes everything created by make.

Executing make clean will remove object files, but not ntl.a.

Building a Shared Library

By default, the above installation procedure builds a static library only. Static libraries are nice because the procedures for building and using them are nearly identical across various flavors of Unix. However, static libraries have their drawbacks, and sometimes it is desirable to build a shared library. This can be done (in theory) by simply passing SHARED=on to NTL's configure.

If you set SHARED=on, then behind the scenes, the procedure used by the makefile changes a bit. In particular, the magical program libtool is used to deal with all idiosyncracies of shared libraries. By default, the makefile configures and uses its own libtool script. You can override this behavior by setting configuration variable LIBTOOL to point to another version of libtool. Note that if SHARED=on, then in addition to using the libtool program, the makefile relies on features specific to GNU make.

On Cygwin, you may need to set LIBTOOL_LINK_FLAGS=-no-undefined for very obscure reasons.

There is also a makefile varibale LIBTOOL_LINK_LIBS that the configutation script automatically sets to -lpthread when NTL_THREADS=on (which is the default) and you are building a shared library. This is passed to the libtool script, and it allows you to forgo passing -pthread when linking your own programs against NTL. You can supply an explicit value to LIBTOOL_LINK_LIBS when you run NTL's configuration script to override this behavior.

Note that if you want to build NTL as a shared library, then (if you use them) GMP and gf2x must also be built and installed as shared libraries. Also note that to use a shared library version of NTL, you may have to do something special, like set a special shell variable: the output generated by the libtool program during make install should give specific instructions. On many systems, you need to set the shell variable LD_LIBRARY_PATH to a path that contains the directory where the shared library is installed.

In addition, if NTL is built as a shared library, then you typically do not have to include -lgmp (if using GMP), or -lgf2x (if using gf2x), or corresponding -L flags, or -lm on the command line when compiling programs that use NTL. As mentioned above, you can typically also forgo including -pthread on the command line.

Thread safety, thread boosting, and exception safety

By default, NTL currently compiles with multithreading enabled. In particular, the configuration variables NTL_THREADS and NTL_THREAD_BOOST are both "on" by default. With NTL_THREADS=on, NTL is compiled in a thread safe manner. With NTL_THREAD_BOOST=on, NTL will make use of a thread pool to boost performance. This also makes the same thread-boosting facility available to NTL client code. Turning off NTL_THREADS will also turn off NTL_THREAD_BOOST.

To provide multithreading safety and capabilities, NTL requires a C++11 compiler. Currently, the configure script will try to add -std=c++11 (if necessary) and -pthread to CXXAUTOFLAGS, as this is what GCC requires.

Note that GMP is thread safe.

Note that gf2x is thread safe starting from v1.2 of gf2x. The NTL build process will check that you have the right version of gf2x.

By default, NTL treats errors in a very old-fashioned way: by printing an error message and aborting your program. However, you can override this behavior by configuring with NTL_EXCEPTIONS=on. This will make NTL throw an exception instead of aborting. This feature also requires a C++11 compiler (and CXXAUTOFLAGS is adjusted appropriately). It is not enabled by default because (a) most NTL clients probably don't need fancy exception handling, and (b) there is a small performance penalty for enabling exceptions (mostly related to esoteric issues surrounding "nothrow move constructors" and vector reallocation, not to anything directly related to exceptions).

[See here] for more details about thread safety and exceptions.

[See here] for more information about thread pools and thread boosting.

32-bit and 64-bit ABIs

An ABI (Application Binary Interface) defines the sizes of various C data types. Typically, with a 32-bit ABI, int's and long's are 32 bits, while on a 64-bit ABI, int's are 32 bits and long's are 64 bits. Some platforms support both 64-bit and 32-bit ABI's; typically in such settings, the 64-bit ABI will yield much better performance, while the 32-bit ABI is available for backward compatibility. On modern 64-bit platforms, the 64-bit ABI is typically the default; otherwise, you may have to explicitly request it (e.g., with GCC, pass the -m64 flag to the compiler).

If you are using NTL with either the GMP or gf2x libraries, then these must be built with the same ABI as NTL. The installation script for GMP will typically select the 64-bit ABI automatically if it is available. The installation script for gf2x may need some hints.

When compiling programs that use NTL, you must also ensure that the program is compiled with the same ABI as NTL.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-examples.html0000644417616742025610000000175014064716023020421 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples
[Previous] [Up] [Next]

A Tour of NTL: Examples


Perhaps the best way to introduce the basics of NTL is by way of example. Browse the following for a number of examples that illustrate some aspects of the functionality and programming interface of NTL.

  1. Big Integers
  2. Vectors and Matrices
  3. Polynomials
  4. Modular Arithmetic
  5. Extension Rings and Fields
  6. Floating Point Classes
  7. Thread Pools
ntl-11.5.1/doc/tour-roadmap.html0000644417616742025610000001324314064716023020226 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: NTL past, present, and future
[Previous] [Up] [Next]

A Tour of NTL: NTL past, present, and future


Some History

Work on NTL started around 1990, when I wanted to implement some new algorithms for factoring polynomials over finite fields. I found that none of the available software was adequate for this task, mainly because the code for polynomial arithmetic in the available software was too slow. So I wrote my own. My starting point was Arjen Lenstra's LIP package for long integer arithmetic, which was written in C. It soon became clear that using C++ instead of C would be much more productive and less prone to errors, mainly because of C++'s constructors and destructors which allow memory management to be automated. Using C++ has other benefits as well, like function and operator overloading, which makes for more readable code.

One of the basic design principles of LIP was portability. I adopted this principle for NTL as well, for a number of reasons, not the least of which was that my computing environment kept changing whenever I changed jobs. Achieving portability is getting easier as standards, like IEEE floating point, get widely adopted, and as the definition of and implementations of the C++ language stabilize.

Since 1990, NTL has evolved in many ways, and it now provides a fairly polished and well-rounded programming interface.

When I started working on NTL, there really were not that many good, portable long integer packages around. Besides LIP, there was the BSD Unix MP library. The first version of GMP was released in the early 1990's. At that point in time, LIP seemed like the best starting point. LIP remains a reasonable long integer package, but in recent years, GMP has really become quite good: it seems well supported on many platforms, and is typically much faster than LIP.

I've now re-structured NTL so that one can use either 'traditional' LIP or GMP as the long integer package.

The Future of NTL

As you can well imagine, there is potentially no end to algorithms one could implement. That is why I have to stop somewhere. I think NTL has reached a point where it provides a reasonably well-rounded suite of algorithms for basic problems. I plan to continue supporting NTL, fixing bugs and improving performance.

While I don't have time to add significant new functionality to NTL, there seems to be an ever-growing number of NTL users out there, and I encourage them to make their code available to others. These might be in the form of NTL "add ons", but there is the possibility of integrating new functionality or algorithmic improvements into NTL itself.

Wish list

These are a few things I wish others could perhaps contribute to NTL. I'd be happy to discuss and assist with any design and integration issues, or any other ideas for improvement. I'd also be happy to discuss ideas for making NTL more open to make it easier for others to contribute.

  • Support for bivariate polynomial arithmetic, including GCDs, resultants, and factoring, and for integer and all the various finite field coefficient rings.

  • Code for elliptic curves, including an elliptic curve point counting algorithm.

  • Integer factorization algorithms.

  • Implementations of some of the newer lattice basis reduction algorithms.

  • Improvements to the polynomial multiplication algorithms over ZZ could be improved. One specific improvement: the Schoenhage-Strassen algorithm currently does not incorporate the so-called "square root of two trick".

  • Improvements to zz_pX arithmetic. For small p, it is likely faster to use Kronecker-substitution to reduce zz_pX multiplication to ZZ multiplication. This is especially true if GMP is used for ZZ arithmetic. Implementing this should not be too hard, but then one would have to go through all of the zz_pX code to make all other operations directly reduce to multiplication in zz_pX. This will be a bit tedious, but it shouldn't be too difficult, since one can copy and paste corresponding code from zz_pEX, where this that already been done.

  • Improvements to some of the RR algorithms. In particular, the trig, exp, and log functions are currently woefully inefficient.

Some things I plan to work on

Here are a few things I plan to work on in the near future.

  • Now that NTL is thread safe, it is possible to use multiple cores within NTL to improve performance. One possibilty is to utilize multiple cores in the modular FFT implementation of polynomial multiplication. Both the FFT (over different small primes) and reduce/CRT (over different coefficients) steps are trivially parallelizable.

  • Introduce some C++11 features, like "move constructors" and "move assignment". This would have to be done with compile-time flags to support older compilers.

  • If nobody else will do it, I will eventually do the zz_pX improvements outlined above.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-win.html0000644417616742025610000001627614064716023017411 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Obtaining and Installing NTL for Windows
[Previous] [Up] [Next]

A Tour of NTL: Obtaining and Installing NTL for Windows


The WinNTL distribution of NTL can be used on any Windows platform. The source code is identical to the UNIX NTL distribution; only the packaging is slightly different. The config.h and mach_desc.h files are geared towards Windows and the MSVC++ compiler.

Windows Users: you should consider using a Unix emulation environment like Cygwin or MinGW, instead of Microsoft development tools.

Why?

  • These environments use gcc, which generally adheres closer to language standards and produces more efficient code that Microsoft's compiler.

  • With these environments, you can use NTL's Unix distribution, and the installation is almost entirely automatic: no pointing and clicking -- not much more than ./configure and make. You can also easily to install GMP and run NTL's performance-tuning Wizard. These factors combined can make a hige difference in performance, easily giving you a huge (10x or more) performance improvement.

  • On 64-bit machines, you should definitely consider Cygwin: the 64-bit version of Cygwin gives you an LP64 data model, which for many reasons is preferable to the Windows data model. In particular, you will get the most performance out of NTL in this environment.

The remaining instructions on this page only apply if you do not use a Unix emulation environment like Cygwin or MinGW.

If you really want to get the most out of NTL, please stop, and seriously consider using a Unix emulation environment and NTL's Unix distribution. Your code will be much snappier, and your quality of life will be much better.

You have been warned.

Obtaining and unpacking NTL.

To obtain the source code and documentation for NTL, download WinNTL-xxx.zip. Here, "xxx" is the current version number. Then unzip this file into a directory (folder). This will unpack everything into a directory called "WinNTL-xxx". Inside this directory, you will find several directories.

  • The directory "doc" contains all of NTL's documentation, including this "tour" ("tour.html") and the ".txt" files explaining each module, which can be accessed directly, or through the "tour".

  • The directory "src" contains all of the source files for the library, all with ".cpp" extensions.

  • The directory "include" contains a single directory called "NTL", and the latter contains all of the ".h" files.

Platform dependent macros.

In directory "include/NTL" there is a file called "mach_desc.h", which contains all of the platform-dependent macro definitions. The default settings should be good for Windows with MSVC++.

You might consider compiling and running the program MakeDesc, whose source files are in directory "MakeDesc". This program will dynamically build a correct "mach_desc.h" for your platform (processor, compiler, run-time environment). To get accurate results, you must compile this program using the level of optimization (or higher) that you will use for NTL. The program will print some diagnostics to the screen, and create the file "mach_desc.h" (in the current directory, and not in the "include/NTL" directory, where it needs to go).

Configuration flags.

Also in directory "include/NTL" is a file called "config.h". You can edit this file to override some of NTL's default options for basic configuration and performance. Again, the defaults should be good for Windows with MSVC++.

Test programs.

The directory "tests" contains several test programs. For each program FooTest, there is a source file "FooTest.cpp", and optionally two files "FooTestIn" and "FooTestOut". If the latter exist, then the program should be run with the "FooTestIn" as standard input; correct output (printed to standard output) should match the contents of "FooTestOut" exactly; note that these programs also print diagnostic output on the screen (through standard error output).

Timing functions.

The directory "GetTime" contains several alternative definitions of the GetTime() function. The file "GetTime.cpp" in the "src" directory should be good for Windows with MSVC++. In a different environment, one of the definitions in the directory "GetTime" better.

Other tools.

The directory "misc" contains the program gen_gmp_aux.cpp that automatically generates the auxilliary file needed when using NTL with GMP. You will have to look at the makefile in the Unix distribution to see how to use these.

Compiling NTL.

It is straightforward to install NTL on Windows with MSVC++, even though it involves a lot of annoying pointing and clicking. First, compile all of the files in "src", and create a static library. Make sure the compiler knows where to find NTL's include files (directory "include" and not "include/NTL") Then, to compile a program using the library, make sure the compiler knows about the library and the directory of NTL's include files.

Here is a link to a video showing how NTL can be built using a Microsoft compiler.

Further remarks.

TIP: When writing programs using NTL, you should include files using the syntax

   #include <NTL/ZZ.h>
and not using a backslash ("\") as a delimiter.

TIP: When writing windows applications using NTL (as opposed to console applications) you might want to compile your program with the NTL_NO_MIN_MAX macro defined. This suppresses the declaration of several min and max functions in file tools.h that conflict with macro names in the MFC header files. Do not attempt to build the library with this macro defined -- only programs that use the library. Another solution is to define the macro NOMINMAX, which will tell the Microsoft compiler to not define min/max macros.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-impl.html0000644417616742025610000003415114064716023017545 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: NTL Implementation and Portability
[Previous] [Up] [Next]

A Tour of NTL: NTL Implementation and Portability


NTL is designed to be portable, fast, and relatively easy to use and extend.

To make NTL portable, no assembly code is used (well, almost none, see below). This is highly desirable, as architectures are constantly changing and evolving, and maintaining assembly code is quite costly. By avoiding assembly code, NTL should remain usable, with virtually no maintenance, for many years.

Minimal platform requirements

When the configuration flag NTL_CLEAN_INT is on (this is not the default, see below), NTL makes two requirements of its platform, neither of which are guaranteed by the C++ language definition, but are essentially universal:
  1. int and long quantities, respectively, are represented using a 2's complement representation whose width is equal to the width of unsigned int and unsigned long, respectively.
  2. Double precision floating point conforms to the IEEE floating point standard.

NTL makes very conservative requirements of the C++ compiler:

  • it is assumed that the C++ compiler conforms to the 1998 standard, including the basic of templates;
  • it does not assume any features not in the 1998 standard, unless compiled with a flag that requires features from the 2011 standard (NTL_THREADS, NTL_EXCEPTIONS, NTL_SAFE_VECTORS) or a flag that explicitly requests a standard (NTL_STD_CXX11, NTL_STD_CXX14).

At some point in the future, it is expected that NTL will move to requiring the 2011 standard or later.

The NTL_CLEAN_INT flag

The configuration flag NTL_CLEAN_INT is currently off by default.

When this flag is off, NTL makes a couple of other requirements of its platform.

First, that conversions from unsigned long to long convert the bit pattern without change to the corresponding 2's complement signed integer. Note that the C++ standard defines the behavior of converting unsigned to signed values as implementation defined when the value cannot be represented in the range of nonnegative signed values. Nevertheless, this behavior is essentially universal, and more importantly, is is not undefined behavior: implementation-defined behavior must be documented and respected by the compiler, while undefined behavior can be exploited by the compiler in some surprising ways.

Second, right shifts of signed integers are consistent, in the sense that if it is sometimes an arithmetic shift, then it is always an arithmetic shift (the installation scripts check if right shift appears to be arithmetic, and if so, this assumption is made elsewhere). Arithmetic right shift is also implementation defined behavior that is essentially universal.

It seems fairly unlikely that one would ever have to turn the NTL_CLEAN_INT flag on, but it seems a good idea to make this possible, and at the very least to identify and isolate the code that relies on these asumptions. Actually, the most recent versions of NTL (especially since v10.0), there is very little such code remaining, and it is not really all that critical to performance any more. Eventually, all such code may disappear completely.

Some floating point issues

NTL uses double precision floating point arithmetic in a number of places, including a number of exact computations, where one might not expect to see floating point. Relying on floating point may seem prone to errors, but with the guarantees provided by the IEEE 754 standard, one can prove the correctness of the NTL code that uses floating point.

Generally, NTL assumes that the IEEE standard is correctly implemented. In particular, it assumes that the compiler issues instructions that respect the grouping of floating point operations. For example, the compiler is not allowed to compile (a+b)+c as a+(b+c), or a*b + a*c as a*(b+c).

By default, most compilers will satisfy this assumption at normal optimization levels (for example, at the -O2 optimization level of most compilers). One should avoid higher optimization levels like -O3 or special flags like -Ofast. In practice, these optimization flags do not help much, and may result in incorrect code. One important compiler which does not satisfy this assumption by default is Intel's icc compiler: one has to pass the -fp-model precise flag to icc to correct this problem. NTL's configuration script will take care of this automatically, by including -fp-model precise in the CXXAUTOFLAGS make variable, so you shouldn't have to worry about it.

It should be said that most floating point code in NTL is quite robust, and will still work correctly under somewhat weaker assumptions. Moreover, NTL's header files are structured so that programs that use NTL do not need to be compiled in a way that satisfies these assumptions. For example, NTL client code could be compiled using icc's defaults or using gcc with the -Ofast flag.

There are a few other issues to address.

  • Extended precision. Standard compliant compilers may compute intermediate results in extended precision. The only machine for which the extended precision is an issue are old (pre-SSE) x86 machines that rely exclusively on the x87 coprocessor instruction set.

  • Contractions and FMA. Standard compliant compilers may "contract" certain sequences of operations into a single operation with just one rounding. The main issue here is that many newer machines have a "fused multiply-add (FMA)" instruction that computes a*b+c with just a single rounding, and compilers may choose generate this instruction.

    Except for one module, NTL works perfectly well even with extended precision and/or contractions. The one exception is the quad_float, which requires strict adherence to the above floating point assumptions, and in addition, requires that all computations are carried out without extended precision or contractions. NTL goes to great lengths to detect and work around these issues, so you should not have to worry about it. More details can be found in quad_float.txt.

  • Special values. The compiler should handle special values (infinities, NaN's, signed zeroes, denormalized numbers) correctly.

    NTL does not rely very much on these for its own computations. For certain operations (like conversions) it assumes that and infinities and NaN's behave as expected so they can be detected. It in some bounds checking code, it assumes that infinities basically work the right way. NTL does not make any assumptions about signed zeros or denormalized numbers.

  • Conversions. The compiler should convert double's to long's by truncation. It should should convert long's to double's exactly if possible, and otherwise, to either the next lower or higher representable value. This behavior is required by the C++ standard.

  • Rounding modes. On some platforms, it is possible to dynamically change the rounding mode from the default round-to-nearest mode to other modes (e.g., round to zero).

    The core algorithms in NTL that use floating point to assist in computing exact integer results are conservatively designed so that they will work in any rounding mode. However, it is not recommended to run NTL code in non-default rounding modes. First, NTL has not been thoroughly tested in these other modes. Second, some higher-level floating-point code (such as quad_float) may not give expected results in other modes.

Algorithms

NTL makes fairly consistent use of asymptotically fast algorithms.

Long integer multiplication is implemented using the classical algorithm, crossing over to Karatsuba for very big numbers. Long integer division is currently only implemented using the classical algorithm -- unless you use NTL with GMP (version 3 or later), which employs an algorithm that is about twice as slow as multiplication for very large numbers.

Polynomial multiplication and division is carried out using a combination of the classical algorithm, Karatsuba, the FFT using small primes, and the FFT using the Schoenhagge-Strassen approach. The choice of algorithm depends on the coefficient domain.

Many algorithms employed throughout NTL are inventions of the author (Victor Shoup) and his colleagues Joachim von zur Gathen and Erich Kaltofen, as well as John Abbott and Paul Zimmermann.

Thread safety

As of v7.0, NTL is thread safe. That said, there are several things to be aware of:

  • To use this feature, you have to enable NTL_THREADS in the configuration script. Also, you will need a compiler and runtime library that implements several key C++11 features, including thread_local storage.
    • NOTE: as of v9.8, the requirements have been relaxed, so that for gcc and gcc-compatible compilers (such as clang and icc) only support of the gcc __thread storage specifier is required.
    • With these relaxed requirements, it is possible to build a thread safe version of NTL on Linux using gcc 4.8 and above, or on Mac OSX 10.10 and above.

  • Prior to v10.0 of NTL, you had to use NTL with GMP to get thread safety. Since v10.0, this requirement has been dropped.

  • As of v11.0, NTL_THREADS is on by default.

  • If you use the external gf2x library, you must use version 1.2 of that library or later. Earlier versions are not thread safe.
To obtain thread safety, I used the following strategies:

  • In places where NTL's interface demands global variables, such as the "current modulus" for the ZZ_p class, these global variables have been made thread local. So, you can pass around various ZZ_pContext objects among threads, and individual threads can install these locally. Thus, different threads can concurrently use the same or different moduli, and it all just works, with no changes to NTL's interface.

  • In places where NTL used static variables to hold on to space for scratch variables, I make these variables thread local, and I also make sure the storage used by these variables get released when the thread terminates. In all NTL builds (thread safe or not), I try to make sure that fairly large chunks of memory get released immediately.

  • In places where NTL uses a lazy strategy to build various tables (such as FFT primes), I uses a "double checked locking" strategy to grow these tables in a way that (a) the tables can be shared among different threads, and (b) taking a lock on a mutex is very rare. The new C++11 concurrent memory model is essential here.

  • Smart pointers (for things like ZZ_pContext's) are designed to do the necesary reference counting in a thread-safe manner.

  • For psuedo-random number generation, the internal state of the PRG is thread local, and the default initial seed is guaranteed to be unique among all threads in a given process (and an attempt is made to make the seed globally unique among all processes and threads, but this is hard to do in a completely portable way).
The overall structure of the code has been modified so that the code base is nearly identical for regular and thread-safe builds: there are just a few ifdef's on the NTL_THREADS flag.

Thread Boosting

As of v9.5.0, NTL provides a thread boosting feature. With this feature, certain code within NTL will use available threads to speed up computations on a multicore machine. This feature is enabled by setting NTL_THREAD_BOOST=on during configuration. See BasicThreadPool.txt for more information.

As of v11.0, NTL_THREAD_BOOST is on by default.

This feature is a work in progress. As time goes on, more and more code within NTL is being thread boosted.

Error Handling and Exceptions

As of v8.0, NTL provides error handling through exceptions. To enable exptions, you have to configure NTL with NTL_EXCEPTIONS flag turned on. By default, exceptions are not enabled, and NTL reverts to its old error handling method: abort with an error message.

If exceptions are enabled, then instead of aborting your program, and appropriate exception is thrown. More details ion the programming interface of this feature are available here.

If you enable exceptions, you must use a C++11 compiler. Specifically, your compiler will need support for lambdas (which are used to conveniently implement the "scope guard" idiom), and your compiler should implement the new default exception specification semantics (namely, that destructors are "noexcept" by default).

Implementation of this required a top-to-bottom scrub of NTL's code, replacing a lot of old-fashioned code with more modern, RAII-oriented code (RAII = "resource acquisition is initialization").

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-struct.html0000644417616742025610000013130214064716023020124 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Programming Interface
[Previous] [Up] [Next]

A Tour of NTL: Programming Interface


In this section, we give a general overview of the NTL's programming interface. The following section has links to detailed documentation on each and every class and function.

Note that only those classes and functions documented in these pages are a part of the "official API": all other interfaces are subject to change without notice.

Basic Ring Classes

The basic ring classes are:

  • ZZ: big integers
  • ZZ_p: big integers modulo p
  • zz_p: integers mod "single precision" p
  • GF2: integers mod 2
  • ZZX: univariate polynomials over ZZ
  • ZZ_pX: univariate polynomials over ZZ_p
  • zz_pX: univariate polynomials over zz_p
  • GF2X: polynomials over GF2
  • ZZ_pE: ring/field extension over ZZ_p
  • zz_pE: ring/field extension over zz_p
  • GF2E: ring/field extension over GF2
  • ZZ_pEX: univariate polynomials over ZZ_pE
  • zz_pEX: univariate polynomials over zz_pE
  • GF2EX: univariate polynomials over GF2E

All these classes all support basic arithmetic operators

   +, -, (unary) -, +=, -=, ++, --, 
   *, *=, /, /=, %, %=.

However, the operations

   %, %=
only exist for integer and polynomial classes, and do not exist for classes
  ZZ_p, zz_p, GF2, ZZ_pE, zz_pE, GF2E.

The standard equality operators (== and !=) are provided for each class. In addition, the class ZZ supports the usual inequality operators.

The integer and polynomial classes also support "shift operators" for left and right shifting. For polynomial classes, this means multiplication or division by a power of X.

Floating Point Classes

In addition to the above ring classes, NTL also provides three different floating point classes:

  • xdouble: "double precision" floating point with extended exponent range (for very large numbers);
  • quad_float: "quasi" quadruple-precision floating point;
  • RR: aribitrary precision floating point.

Vectors and Matrices

There are also vectors and matrices over

   ZZ ZZ_p zz_p GF2 ZZ_pE zz_pE GF2E RR
which support the usual arithmetic operations.

Functional and Procedural forms

Generally, for any function defined by NTL, there is a functional form, and a procedural form. For example:

   ZZ x, a, n;
   x = InvMod(a, n);  // functional form
   InvMod(x, a, n);   // procedural form

This example illustrates the normal way these two forms differ syntactically. However, there are exceptions. First, if there is a operator that can play the role of the functional form, that is the notation used:

   ZZ x, a, b;
   x = a + b;    // functional form
   add(x, a, b); // procedural form

Second, if the functional form's name would be ambiguous, the return type is simply appended to its name:

   ZZ_p x;
   x = random_ZZ_p();  // functional form
   random(x);          // procedural form

Third, there are a number of conversion functions (see below), whose name in procedural form is conv, but whose name in functional form is conv<T>, where T is the return type:

   ZZ x;  
   double a;

   x = conv<ZZ>(a);  // functional form
   conv(x, a);       // procedural form

The use of the procedural form may be more efficient, since it will generally avoid the creation of a temporary object to store its result. However, it is generally silly to get too worked up about such efficiencies, and the functional form is usually preferable because the resulting code is usually easier to understand.

The above rules governing procedural and functional forms apply to essentially all of the arithmetic classes supported by NTL, with the exception of xdouble and quad_float. These two classes only support the functional/operator notation for arithmetic operations (but do support both forms for conversion).

Conversions and Promotions

As mentioned above, there are numerous explicit conversion routines, which come in both functional and procedural forms. A complete list of these can be found in conversions.txt. This is the only place these are documented; they do not appear in the other ".txt" files.

It is worth mentioning here, however, that generic conversion operators are provided for vectors and matrices, which act component-wise. For example, since there is a conversion from ZZ to RR, there is automatically a conversion from Vec<ZZ> to Vec<RR>.

Even though there are no implicit conversions, users of NTL can still have most of their benefits. This is because all of the basic arithmetic operations (in both their functional and procedural forms), comparison operators, and assignment are overloaded to get the effect of automatic "promotions". For example:

   ZZ x, a;

   x = a + 1;
   if (x < 0
      mul(x, 2, a);
   else
      x = -1;

These promotions are documented in the ".txt" files, usually using a kind of "short hand" notation. For example:

ZZ operator+(const ZZ& a, const ZZ& b);

// PROMOTIONS: operator + promotes long to ZZ on (a, b).

This means that in addition to the declared function, there are two other functions that are logically equivalent to the following:

ZZ operator+(long a, const ZZ& b) { return ZZ(a) + b; }
ZZ operator+(const ZZ& a, long b) { return a + ZZ(b); }

Note that this is not how NTL actually implements these functions. It is in generally more efficient to write

   x = y + 2;

than it is to write

   x = y + ZZ(2);

The former notation avoids the creation and destruction of a temporary ZZ object to hold the value 2.

Also, don't have any inhibitions about writing tests like

   if (x == 0) ...

and assignments like

   x = 1

These are all optimized, and do not execute significaltly slower than the "lower level" (and much less natural)

   if (IsZero(x)) ...

and

   set(x);

Some types have even more promotions. For example, the type ZZ_pX has promotions from long and ZZ_p. Thus, the add function for ZZ_pX takes the following argument types:

   (ZZ_pX, ZZ_pX), (ZZ_pX, ZZ_p), (ZZ_pX, long), (ZZ_p, ZZ_pX), (long, ZZ_pX)
Each of these functions effectively converts the argument to be promoted to a ZZ_pX.

Note that when promoting a pair of arguments, at least one of the arguments must be of the target type.

I have tried to be very consistent with these promotions so that one usually won't need to hunt through the documentation. For a given type, there is a natural, fixed set of types that promote to it. Here is the complete list:

   destination  source
   
   xdouble      double
   quad_float   double
   RR           double
   ZZ           long
   ZZ_p         long
   ZZ_pX        long, ZZ_p
   zz_p         long
   zz_pX        long, zz_p
   ZZX          long, ZZ
   GF2          long
   GF2X         long, GF2
   GF2E         long, GF2
   GF2EX        long, GF2, GF2E
   ZZ_pE        long, ZZ_p
   ZZ_pEX       long, ZZ_p, ZZ_pE
   zz_pE        long, zz_p
   zz_pEX       long, zz_p, zz_pE

All the promotions are documented, but here are a few general rules describing the available promotions:

  • All classes provide explicit constructors for promoted types. For example,

       ZZ w = ZZ(1);
       ZZ x(1);  // allowed
       ZZ y{1};  // allowed in C++11
       ZZ z = 1// not allowed

  • Promotions apply uniformly to both procedural and functional forms, as well as to the corresponding assignment operator forms. E.g.,

       x = x + 2;
       add(x, x, 2);
       x += 2;

  • The addition, subtraction, multiplication, equality and comparison routines always promote both arguments. E.g.,

       x = 2 + y;
       add(x, 2, y);
       if (3 > x || y == 5) ...

  • The assignment operator always promotes the right-hand side. E.g.,

       x = 2;

  • For non-integer, non-polynomial types, the division routine promotes both arguments. E.g.,

       RR x, y, z;
          ...
       x = 1.0/y;
       z = y/2.0;

    For integer or polynomial types, the division routine promotes the denominator only. E.g.,

       ZZ x, y;
          ...
       y = x/2;
    
  • Matrix by scalar and vector by scalar multiplication promote the scalar. E.g.,

       Vec<ZZ> v, w;
          ...
       v = w*2;
       v = 2*w;
       v *= 2;

  • The monomial constructors for polynomials and the corresponding SetCoeff routines promote the coefficient argument. E.g.,

       ZZX f;
       f = ZZX(INIT_MONO, 35);  // f == 5*X^3
       SetCoeff(f, 02);  // f == 5*x^3 + 2;

  • In module ZZ, the modular arithmetic routines, as well as the bit-wise and, or, and xor routines promote their arguments. There are also several other routines in module ZZ that have both ZZ and long versions, e.g., NumBits, bit, weight. Check the documentation in ZZ.txt for complete details.

Some Conversion and Promotion Technicalities

Usually, conversions and promotions are semantically equivalent. There are three exceptions, however.

One exception is conversion of floating point double to ZZ. The safest way to do this is to apply an explicit conversion operator, and not to rely on promotions. For example, consider

   ZZ a; double x;

   a = a + x;

This is equivialent to

   a = a + long(x);

and to

   a = a + ZZ(x);

One could also use an explicit conversion function:

   a = a + conv<ZZ>(x);

This last version guarantees that there is no loss of precision, and also guarantees that the floor of x is computed. With the first version, one may lose precision when x is converted to a long, and also the direction of truncation for negative numbers is implementation dependent (usually truncating towards zero, instead of computing the floor).

The second exception is conversion of unsigned int or unsigned long to ZZ. Again, the safest way to do this is with an explicit conversion operator. As above, if one relies on promotions, the unsigned integer will be first converted to a signed long, which is most likely not what was intended.

The third exception can occur on 64-bit machines when converting a signed or unsigned long to one of NTL's extended precision floating-point types (RR or quad_float). These types only provide promotions from double, and converting a long to a double on a 64-bit machine can lead to a loss of precision. Again, if one uses the appropriate NTL conversion routine, no loss of precision will occur.

Another pitfall too avoid is initialzing ZZ's with integer constants that are too big. Consider the following:

   ZZ x;
   x = 1234567890123456789012;

This integer constant is too big, and this overflow condition may or may not cause your compiler to give you a warning or an error. The easiest way to introduce such large constants into your program is as follows:

   ZZ x;
   x = conv<ZZ>("1234567890123456789012");

Conversion functions are provided for converting C character strings to the types ZZ, RR, quad_float, and xdouble.

One should also be careful when converting to RR. All of these conversions round to the current working precision, which is usually, but not always, what one wants.

Input and Output

NTL provides input and output operators for all types, using the usual conventions for input and output streams. If an input error occurs, the "fail bit" of the input stream is set, and the input variable remains unchanged.

Although conversions from C-style character strings to the types ZZ, xdouble, quad_float, and RR are provided, one can always read and write to C++ character streams using the stringstream class from the standard library, in conjunction with the input and output operators provided by NTL.

Aliasing

An important feature of NTL is that aliasing of input and output parameters is generally allowed. For example, if you write mul(x, a, b), then a or b may alias (have the same address as) x (or any object that x contains, e.g., scalar/vector or scalar/polynomial multiplication).

One exception to this rule: the generic conversions provided for vectors and matrices assume that their inputs do not alias their outputs.

Constructors, Destructors, and Memory Management

NTL generally takes care of managing the space occupied by large, dynamically sized objects, like objects of class ZZ or any of NTL's dynamic vectors. However, it is helpful to understand a little of what is happening behind the scenes.

Almost all classes are implemented as a pointer, and the default constructor just sets this pointer to 0. Space is allocated for the object as needed, and when the object's destructor is called, the space is freed.

Copies are "deep" rather than "shallow". This means the data itself is copied, and not just a pointer to the data. If the destination object does not have enough space to hold the source data, then the space held by the destination object is "grown". This is done using the C routine realloc(). Note, however, that if the source object is smaller than the destination object, the space held by the destination object is retained. This strategy usually yields reasonable behaviour; however, one can take explicit control of the situation if necessary, since almost all NTL classes have a method kill() which frees all space held by the object, and sets its state to the default initial state (a value 0 or a zero-length vector).

The only exception to the above is the class ZZ_pContext, and the analogous classes for zz_p, ZZ_pE, zz_pE, and GF2E. These objects are implemented as referenced-counted pointers, and copies are "shallow".

While we are discussing initialization, there is one technical point worth mentioning. It is safe to declare global objects of any NTL type as long as one uses only the default constructor. For example, the global declarations

   ZZ global_integer;
   Vec<ZZ_p> global_vector;

should always work, since their initialization only involves setting a pointer to 0. However, one should avoid initializing global objects with non-default constructors, and should avoid doing anything that would lead to non-trivial computations with NTL objects prior to the beginning of the execution of routine main(). The reasons for this are quite esoteric and can only be appreciated by a true C++ afficianado. Actually, most such initializations and computations probably will work, but it is somewhat platform dependant.

Normal people usually do none of these things, so all of this should not matter too much. There is, however, one possible exception to this. A programmer might want to have a global constant initialized like this:

   const quad_float Pi = conv<quad_float>("3.1415926535897932384626433832795029");

While this probably will work fine on most platforms, it may not be an entirely portable construction, since it will involve a non-trivial computation before execution of main() begins. A more portable strategy is to define a function returning a read-only reference:

   const quad_float& Pi()
   {
      static quad_float pi = 
         conv<quad_float>("3.1415926535897932384626433832795029");
      return pi;
   }

and then call the function Pi() to get a read-only reference to this constant value:

   area = Pi()*r*r;

The initialization will then take place the first time Pi() is called, which is presumably after main() starts, and so everything should work fine. This is a very simple and general strategy that most C++ experts recommend using whenever the initialization of a non-global object requires non-trivial computation.

Residue class rings and modulus switching

NTL provides a number of classes to represent residue class rings:

   ZZ_p, zz_p, GF2, ZZ_pE, lzz_pE, GF2E.
For each such class, except GF2, there is a global, current modulus.

We focus on the class ZZ_p, but similar comments apply to the other residue class types. For example, for ZZ_p, you can set the current modulus to p as follows:

   ZZ_p::init(p);

The current modulus must be initialized before any operations on ZZ_p's are performed. The modulus may be changed, and a mechanism is provided for saving and restoring a modulus.

Here is what you do to save the current modulus, temporarily set it to p, and automatically restore it:

   { 
      ZZ_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the current modulus. The destructor for push will restore the old modulus when the scope enclosing it exits. This is the so-called RAII (resource acquisition is initialization) paradigm.

You could also do the following:

   {
      ZZ_pPush push; // just backup current modulus

        ...

      ZZ_p::init(p1); // install p1

        ...

      ZZ_p::init(p2); // install p2

      // reinstall original modulus at close of scope
   }

Warning: C++ syntax can be rather unfriendly sometimes. When using RAII objects like ZZ_pPush, watch out for the following errors:

   ZZ_pPush push();  // ERROR: local declaration of a function!!
   ZZ_pPush(p);      // ERROR: temporary RAII-object created and
                     //        immediately destroyed!!

Unfortunately, most compilers do not issue any warnings in these situations. I have fallen into both traps myself.

The ZZ_pPush interface is good for implementing simple stack-like "context switching". For more general context switching, use the class ZZ_pContext:

   ZZ_p::init(p);     // set current modulus to p

      ...

   ZZ_pContext context;
   context.save();    // save the current modulus p

      ...

   ZZ_p::init(q);     // set current modulus to q

      ...
  
   context.restore(); // restore p as the current modulus

Note that ZZ_pContext's are essentially "smart pointers", and they may be copied. Generally speaking, saving, restoring, and copying ZZ_pContext's are very cheap operations. Likewise, saving and restoring contexts using ZZ_pPush objects are very cheap operations.

It is critical that ZZ_p objects created under one ZZ_p modulus are not used in any non-trivial way "out of context", i.e., under a different (or undefined) ZZ_p modulus. However, for ease-of-use, some operations may be safely performed out of context. These safe operations include: the default and copy constructor, the destructor, and the assignment operator. In addition it is generally safe to read any ZZ_p object out of context (i.e., printing it out, or fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may lead to unpredictable behavior.

The implementations of Vec<ZZ_p>, Vec<GF2E>, and Vec<GF2> are specialized to manage memory more efficiently than in the default implementation of Vec<T>:

  • Contiguous elements in a Vec<ZZ_p> are allocated in a contiguous region of memory. This reduces the number of calls to the memory allocator, and leads to greater locality of reference. A consequence of this implementation is that any calls to SetLength on a Vec<ZZ_p> object will need to use information about the current modulus, and so such calls should only be done "in context". That said, it is still safe to construct a Vec<ZZ_p> using the default or copy contructor, and to assign or append one Vec<ZZ_p> to another "out of context".

  • The same strategy is used for Vec<GF2E>'s.

  • In any case, the above restrictions adhere to the general rules for safely using residue class ring objects "out of context".

  • Vec<GF2>'s are implemented by packing coefficients (which are just bits) into words. A mechanism is provided to make indexing these vectors behave like normal vectors, via a class the mimics ordinary references to GF2's.

C+11 Support

As of version 10.4, NTL supports a number of C++11 specific features. To enable this support, you must build NTL with NTL_STD_CXX11=on. This build flag is automatically turned on by a number of other NTL features that require NTL support.

The most important of these is "move semantics". Most of the important classes are now equipped with "move" constructors and "move" assignment operators. Where possible, these are declared noexcept. NTL's Vec class and STL's vector class can take advantage of noexcept move constructors in certain situations. See below for more details regarding exceptions and move semantics.

Error Handling and Exceptions

Prior to version 8.0 of NTL, errors were dealt with in a simlple way: print an error message and abort. As of version 8.0, NTL provides error handling with exceptions. To use this feature, you will need to configure NTL with the NTL_EXCEPTIONS flag turned on. You will also need a C++11 compiler.

The exceptions thrown by NTL are either a std::bad_alloc exception (in case of memory allocation error), or a class (defined in namespace NTL) derived from std::runtime_error:

  • ErrorObjectstd::runtime_error
    • base class
  • LogicErrorObjectErrorObject
    • used to indicate a logic error, such as incorrect function parameters, index out of range, etc.
  • ArithmeticErrorObjectErrorObject
    • used to indicate an arithmetic error, such as divide by zero
  • ResourceErrorObjectErrorObject
    • used to indicate an overflow error (e.g., when a number cannot be stored as a long)
  • FileErrorObjectErrorObject
    • used to indicate a problem opening or closing a file
  • InputErrorObjectErrorObject
    • used to indicate a problem reading from a stream

All of these error objects override the what() method of std::exception with an appropriate error message.

There is also a special exception class InvModErrorObject, which is derived from ArithmeticErrorObject, and is thrown when a modular inverse computation over ZZ fails (either directly, or indirectly through PowerMod computation, or via an inverse computation in ZZ_p). The InvModErrorObject provides two methods, get_a() and get_n(), which provide read-only references to the offending objects a and n (so GCD(a, n) != 1).

The generic class ErrorObject is not thrown directly by any NTL routines, except for the legacy function Error, which is no longer called by any NTL routines. New functions

   MemoryError, LogicError, ArithmeticError, ResourceError, FileError, InputError
are used to throw exceptions derived from ErrorObject.

Efficiency considerations: Because of a bunch of design decsions that were made long before C++11 came along, most of the important NTL classes do not have noexcept move constructors if you enable exceptions in NTL, which can reduce performance somewhat. Therefore, if you do not really need to have NTL handle errors by throwing exceptions, and you do want to maximize performance, you should not enable exceptions in NTL. But even with exceptions enabled, the performance penalty should not be terrible.

Issues with GMP: GMP itself (at least as of version 6.1.2) provides only the very crude print-message-then-abort error handling. Note that NTL only uses low-level GMP routines (the mpn-level routines), and these routines should only abort if they cannot allocate space for temporary big integers within GMP itself. So this should only be an issue of you are working with some very large integers. The GMP developers are working on improving their error handling. When that happens, NTL will inherit these improvements. If you really need proper error handling, and are willing to pay a certain performance penalty, then you should configure and build NTL without GMP.

Issues with gf2x: Similar comments apply to NTL builds that use the gf2x library.

Exception safety: I have tried to carefully document exception safety characterstics for just a few, critical, low-level classes: vectors and matrices (vector.txt and matrix.txt), smart pointer classes (SmartPtr.txt), thread-safe lazy initialization classes (Lazy.txt and LazyTable.txt). Otherwise, it is only safe to assume that NTL functions provide a weak exception-safety guarantee: if an exception is thrown, the stack unwinding process will will not leak any resources and will leave all modified objects in a reasonable state: at least, such objects may be safely destroyed, and may also be assigned to or reset; however, they may not necessarily be safely used as inputs to other functions. When stronger exception safety is required, you can always compute results into dynamically allocated objects pointed to by "smart pointers", and then move or swap these pointers into place after all computations have succeeded.

As NTL provides swap functions for all its major classes, and as swap functions have evolved to play a critical role in writing exception-safe code, they deserve a special mention here:

  • For all classes except ZZ, ZZ_p, GF2X, GF2E, and Vec<T>, the swap function is guaranteed to not throw any exceptions.

  • For ZZ objects that are not elements of a ZZVec, ZZ_p objects that are not elements of a Vec<ZZ_p>, GF2X objects that are not elements of a GF2XVec, and GF2E objects that are not elements of a Vec<GF2E>, the swap function is guaranteed to not throw any exceptions.

  • For Vec<T> objects whose length has not been fixed, the swap function is guaranteed to not throw any exceptions.

  • For the remaining cases, the swap function provides a strong exception-safety guarantee (the operation either succeeds, or throws and leaves data unchanged).
These rules are unfortunatley a bit complicated, due to NTL's historical legacy, and to its special memory management of ZZVec, Vec<ZZ_p>, GF2XVec, and Vec<GF2E> types.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour.html0000644417616742025610000000261414064716023016605 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL

A Tour of NTL


Table of Contents

  1. Introduction
  2. Examples
  3. Programming Interface (Read this to get an overall view on NTL's interfaces and conventions)
  4. Summary of NTL's Main Modules (This contains links to detailed documentation of all classes and functions)
  5. Obtaining and Installing NTL for UNIX
  6. Obtaining and Installing NTL for Windows
  7. Tips for Getting the Best Performance out of NTL
  8. NTL Implementation and Portability
  9. Using NTL with GMP
  10. Using NTL with the gf2x library
  11. Some Performance Data
  12. NTL past, present, and future
  13. Summary of Changes
  14. Acknowledgements


Back to NTL page

Back to Victor Shoup's home page ntl-11.5.1/doc/tour-ex1.html0000644417616742025610000005611614064716023017306 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Big Integers

[Previous] [Up] [Next]

A Tour of NTL: Examples: Big Integers


The first example makes use of the class ZZ, which represents "big integers": signed, arbitrary length integers. This program reads two big integers a and b, and prints (a+1)*(b+1).

#include <NTL/ZZ.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZ a, b, c;

   cin >> a;
   cin >> b;
   c = (a+1)*(b+1);
   cout << c << "\n";
}

This program declares three variables a, b, and c of type ZZ. The values a and b are read from standard input. The value c is then computed as (a+1)*(b+1). Finally, the value of c is printed to the standard output.

Note that one can compute with ZZs much as with ordinary ints, in that most of the standard arithmetic and assignment operators can be used in a direct and natural way. The C++ compiler and the NTL library routines automatically take care of all the bookkeeping involved with memory management and temporary objects.

Note that by default, all of NTL's components are in the namespace NTL; with the "using directive"

   using namespace NTL;
in the above example, one can access these components directly.


Here's a program that reads a list of integers from standard input and prints the sum of their squares.

#include <NTL/ZZ.h>


using namespace std;
using namespace NTL;


int main()
{
   ZZ acc, val;

   acc = 0;
   while (cin >> val)
      acc += val*val;

   cout << acc << "\n";
}

Following the normal conventions for input operators, NTL's input operators will set the "fail bit" of the input stream if the input is missing or ill formed, and the condition in the while loop will detect this.


Here's a simple modular exponentiation routine for computing a^e mod n. NTL already provides a more sophisticated one, though.

ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n)
{
   if (e == 0return ZZ(1);

   long k = NumBits(e);

   ZZ res;
   res = 1;

   for (long i = k-1; i >= 0; i--) {
      res = (res*res) % n;
      if (bit(e, i) == 1) res = (res*a) % n;
   }

   if (e < 0)
      return InvMod(res, n);
   else
      return res;
}

Note that as an alternative, we could implement the inner loop as follows:

   res = SqrMod(res, n);
   if (bit(e, i) == 1) res = MulMod(res, a, n);

We could also write this as:

   SqrMod(res, res, n);
   if (bit(e, i) == 1) MulMod(res, res, a, n);

This illustrates an important point about NTL's programming interface. For every function in NTL, there is a procedural version that stores its result in its first argument. The reason for using the procedural variant is efficieny: on every iteration through the above loop, the functional form of SqrMod will cause a temporary ZZ object to be created and destroyed, whereas the procedural version will not create any temporaries. Where performance is critical, the procedural version is to be preferred. Although it is usually silly to get too worked up about performance, it may be reasonable to argue that modular exponentiation is an important enough routine that it should be as fast as possible.

Note that when the functional version of a function can be naturally named with an operator, this is done. So for example, NTL provides a 3-argument mul routine for ZZ multiplication, and a functional version whose name is operator *, and not mul.

While we are taking about temporaries, consider the first version of the inner loop. Execution of the statement

   res = (res*res) % n;

will result in the creation of two temporary objects, one for the product, and one for the result of the mod operation, whose value is copied into res. Of course, the compiler automatically generates the code for cleaning up temporaries and other local objects at the right time. The programmer does not have to worry about this.


This example is a bit more interesting. The following program prompts the user for an input, and applies a simple probabilistic primality test. Note that NTL already provides a slightly more sophisticated primality test.

#include <NTL/ZZ.h>

using namespace std;
using namespace NTL;

long witness(const ZZ& n, const ZZ& x)
{
   ZZ m, y, z;
   long j, k;

   if (x == 0return 0;

   // compute m, k such that n-1 = 2^k * m, m odd:

   k = 1;
   m = n/2;
   while (m % 2 == 0) {
      k++;
      m /= 2;
   }

   z = PowerMod(x, m, n); // z = x^m % n
   if (z == 1return 0;

   j = 0;
   do {
      y = z;
      z = (y*y) % n; 
      j++;
   } while (j < k && z != 1);

   return z != 1 || y != n-1;
}


long PrimeTest(const ZZ& n, long t)
{
   if (n <= 1return 0;

   // first, perform trial division by primes up to 2000

   PrimeSeq s;  // a class for quickly generating primes in sequence
   long p;

   p = s.next();  // first prime is always 2
   while (p && p < 2000) {
      if ((n % p) == 0return (n == p);
      p = s.next();  
   }

   // second, perform t Miller-Rabin tests

   ZZ x;
   long i;

   for (i = 0; i < t; i++) {
      x = RandomBnd(n); // random number between 0 and n-1

      if (witness(n, x)) 
         return 0;
   }

   return 1;
}

int main()
{
   ZZ n;

   cout << "n: ";
   cin >> n;

   if (PrimeTest(n, 10))
      cout << n << " is probably prime\n";
   else
      cout << n << " is composite\n";
}

Note that in NTL, there are typically a number of ways to compute the same thing. For example, consider the computation of m and k in function witness. We could have written it thusly:

   k = 1;
   m = n >> 1;
   while (!IsOdd(m)) {
      k++;
      m >>= 1;
   }

It turns out that this is actually not significantly more efficient than the original version, because the implementation optimizes multiplication and division by 2.

The following is more efficient:

   k = 1;
   while (bit(n, k) == 0) k++;
   m = n >> k;

As it happens, there is a built-in NTL routine that does just what we want:

   m = n-1;
   k = MakeOdd(m);


Having seen a number of examples involving ZZs, let's look at the ZZ interface in a bit more detail.

Constructors, assignment, and conversions

When you declare an object of type ZZ, the default constructor initializes to the value 0. As we have already seen, there is an assignment operator that allows one to copy the value of one ZZ to another. Note that these copies (like almost all copies in NTL) are "deep", i.e., the actual data is copied, and not just a pointer. Of course, if the amount of space allocated by the destination of the assignment is insufficient to hold the value of the source, space is automatically re-allocated.

One can also assign a value of type long to a ZZ:

   ZZ x;
   x = 1;

Note that one cannot write

   ZZ x = 1;  // error

to initialize a ZZ. Instead, one could write

   ZZ x = ZZ(1);
   ZZ y(1);
   ZZ z{1}; // C++11 only

using the constructor that allows one to explicitly construct a ZZ from a long.

Alternatively, one could write this as:

   ZZ x = conv<ZZ>(1);

This is an example of one of NTL's conversion routines. For very large constants, one can write:

   ZZ x = conv<ZZ>("99999999999999999999");

These examples illustrate conversion routines in their functional forms. Conversion routines are also available in procedural form:

   ZZ x;
   conv(x, 1);
   conv(x, "99999999999999999999");

Functionality

All of the basic arithmetic operators are supported, including comparison, arithmetic, shift, and bit-wise logical operations. One can mix ZZs and longs in any expresion in a natural way. NTL does not support implicit type conversion; rather, for basic operations, it simply overloads the operators or functions in a way to achieve a kind of "promotion logic": if one input is a ZZ and the other is a long (or something that implicitly converts to a long, like an int), the long input is effectively converted to a ZZ. Moreover, wherever possible, the implementation does this as efficiently as possible, and usually avoids the creation of a temporary ZZ.

There are also procedural versions for all the basic arithmetic operations:

   add, sub, negate, mul, sqr, div, rem, DivRem, 
   LeftShift, RightShift,
   bit_and, bit_or, bit_xor

There are many other routines. Here is a brief summary:

  • GCD -- computes greatest common divisor of two integers
  • XGCD -- extended Euclidean algorithm
  • AddMod, SubMod, NegateMod, MulMod, SqrMod, InvMod, PowerMod -- routines for modular arithmetic, including inversion and exponentiation
  • NumBits -- length of binary representation
  • bit -- extract a bit
  • ZZFromBytes, BytesFromZZ -- convert between octet strings and ZZs
  • RandomBnd, RandomBits, RandomLen -- routines for generating pseudo-random numbers
  • GenPrime, ProbPrime -- routines for generating primes and testing primality
  • power -- (non-modular) exponentiation
  • SqrRoot -- integer part of square root
  • Jacobi, SqrRootMod -- Jacobi symbol and modular square root

Most of these functions also have pure long versions as well, and as usual, there are both functional and procedural variants.

There are other functions as well. See ZZ.txt for complete details. Also see tools.txt for some basic services provided by NTL.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex2.html0000644417616742025610000003115514064716023017303 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Vectors and Matrices
[Previous] [Up] [Next]

A Tour of NTL: Examples: Vectors and Matrices


The following routine sums up the numbers in a vector of ZZ's.

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

ZZ sum(const Vec<ZZ>& v)
{
   ZZ acc;

   acc = 0;

   for (long i = 0; i < v.length(); i++)
      acc += v[i];

   return acc;
}

The class Vec<ZZ> is a dynamic-length array of ZZs; more generally, NTL provides a template class Vec<T> for dynamic-length vectors over any type T. Some history is in order here. NTL predates the STL and the vector template found in modern C++. Older versions of NTL (prior to v6) did not use templates, but instead defined generic vectors using macros. By convention, NTL named these vec_T. For backward compatibility, NTL now provides typedefs all these "legacy" vector types.

Vectors in NTL are indexed from 0, but in many situations it is convenient or more natural to index from 1. The generic vector class allows for this; the above example could be written as follows.

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

ZZ sum(ZZ& s, const Vec<ZZ>& v)
{
   ZZ acc;

   acc = 0;

   for (long i = 1; i <= v.length(); i++)
      acc += v(i);

   return acc;
}

Note that by default, NTL does not perform range checks on vector indices. However, there is a compile-time flag that activates range checking. Therefore, it is good practice to always assume that range checking may be activated, and to not access elements that are out of range.


The following example illustrates vector I/O, as well as changing the length of a vector. This program reads a Vec<ZZ>, and then creates and prints a "palindrome".

#include <NTL/ZZ.h>
#include <NTL/vector.h>

using namespace std;
using namespace NTL;

int main()
{
   Vec<ZZ> v;
   cin >> v;

   long n = v.length();
   v.SetLength(2*n);

   long i;
   for (i = 0 ; i < n; i++)
      v[n+i] = v[n-1-i];

   cout << v << "\n";
}

Notice that changing the length of a vector does not change its contents.

When we compile and run this program, if we type in

   [1 -2 3]
as input, the output is
   [1 -2 3 3 -2 1]

See vector.txt for complete details of NTL's generic vector mechanism. Also note that for several fundamental vector types, such as Vec<ZZ>.txt, there is a corresponding header file <NTL/vec_ZZ.h> that defines a number of basic arithmetic operations, as well as provides the typedef typedef vec_ZZ for backward compatibilty. See vec_ZZ.txt for complete details on the arithmetic operations for Vec<ZZ>'s provided by NTL.


There is also basic support for matrices in NTL. In general, the class Mat<T> is a special kind of Vec< Vec< T > >, where each row is a vector of the same length. Row i of matrix M can be accessed as M[i] (indexing from 0) or as M(i) (indexing from 1). Column j of row i can be accessed as M[i][j] or M(i)(j); for notational convenience, the latter is equivalent to M(i,j).

Here is a matrix multiplication routine, which in fact is already provided by NTL.

#include <NTL/ZZ.h>
#include <NTL/matrix.h>

using namespace std;
using namespace NTL;

void mul(Mat<ZZ>& X, const Mat<ZZ>& A, const Mat<ZZ>& B)
{
   long n = A.NumRows();
   long l = A.NumCols();
   long m = B.NumCols();

   if (l != B.NumRows())
      Error("matrix mul: dimension mismatch");

   X.SetDims(n, m); // make X have n rows and m columns

   long i, j, k;
   ZZ acc, tmp;

   for (i = 1; i <= n; i++) {
      for (j = 1; j <= m; j++) {
         acc = 0;
         for(k = 1; k <= l; k++) {
            mul(tmp, A(i,k), B(k,j));
            add(acc, acc, tmp);
         }
         X(i,j) = acc;
      }
   }
}

In case of a dimension mismatch, the routine calls the Error function, which is a part of NTL and which simply prints the message and aborts. That is generally how NTL deals with errors.

This routine will not work properly if X aliases A or B. The actual matrix multiplication routine in NTL takes care of this. In fact, all of NTL's routines allow outputs to alias inputs.

To call NTL's built-in multiplication routine (declared in <NTL/mat_ZZ.h>), one can write

   mul(X, A, B);
or one can also use the operator notation
   X = A * B;

NTL provides several matrix types. See matrix.txt for complete details on NTL's generic matrix mechanism. Also see mat_ZZ.txt for complete details on the arithmetic operations for Mat<ZZ>'s provideed by NTL (including basic linear algebra). Also see LLL.txt for details on routines for lattice basis reduction (as well as routines for finding the kernel and image of a matrix).

One thing you may have noticed by now is that NTL code generally avoids the type int, preferring instead to use long. This seems to go against what most "style" books preach, but nevertheless seems to make the most sense in today's world. Although int was originally meant to represent the "natural" word size, this seems to no longer be the case. On 32-bit machines, int and long are the same, but on 64-bit machines, they are often different, with int's having 32 bits and long's having 64 bits. Indeed, there is a standard, called "LP64", which is being adopted by all Unix-like systems, and which specifies that on 64-bit machines, int's have 32 bits, and long's and pointers have 64 bits. Moreover, on such 64-bit machines, the "natural" word size is usually 64-bits; indeed, it is often more expensive to manipulate 32-bit integers. Thus, for simplicity, efficiency, and safety, NTL uses long for all integer values. If you are used to writing int all the time, it takes a little while to get used to this.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex3.html0000644417616742025610000002706314064716023017307 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Polynomials
[Previous] [Up] [Next]

A Tour of NTL: Examples: Polynomials


NTL provides extensive support for very fast polynomial arithmetic. In fact, this was the main motivation for creating NTL in the first place, because existing computer algebra systems and software libraries had very slow polynomial arithmetic. The class ZZX represents univariate polynomials with integer coefficients. The following program reads a polynomial, factors it, and prints the factorization.

#include <NTL/ZZXFactoring.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZX f;

   cin >> f;

   Vec< Pair< ZZX, long > > factors;
   ZZ c;

   factor(c, factors, f);

   cout << c << "\n";
   cout << factors << "\n";
}

When this program is compiled an run on input

   [2 10 14 6]
which represents the polynomial 2 + 10*X + 14*x^2 +6*X^3, the output is
   2
   [[[1 3] 1] [[1 1] 2]]
The first line of output is the content of the polynomial, which is 2 in this case as each coefficient of the input polynomial is divisible by 2. The second line is a vector of pairs, the first member of each pair is an irreducible factor of the input, and the second is the exponent to which is appears in the factorization. Thus, all of the above simply means that
2 + 10*X + 14*x^2 +6*X^3 = 2 * (1 + 3*X) * (1 + X)^2 

Admittedly, I/O in NTL is not exactly user friendly, but then NTL has no pretensions about being an interactive computer algebra system: it is a library for programmers.

In this example, the type Vec< Pair< ZZX, long > > is an NTL vector whose base type is Pair< ZZX, long >. The type Pair< ZZX, long > is the instantiation of a template "pair" type defined by NTL. See pair.txt for more details.


Here is another example. The following program prints out the first 100 cyclotomic polynomials.


#include <NTL/ZZX.h>

using namespace std;
using namespace NTL;

int main()
{
   Vec<ZZX> phi(INIT_SIZE, 100);  

   for (long i = 1; i <= 100; i++) {
      ZZX t;
      t = 1;

      for (long j = 1; j <= i-1; j++)
         if (i % j == 0)
            t *= phi(j);

      phi(i) = (ZZX(INIT_MONO, i) - 1)/t;  

      cout << phi(i) << "\n";
   }
}

To illustrate more of the NTL interface, let's look at alternative ways this routine could have been written.

First, instead of

   Vec<ZZX> phi(INIT_SIZE, 100);  

one can write

   Vec<ZZX> phi;
   phi.SetLength(100);

Second, instead of

            t *= phi(j);

one can write this as

            mul(t, t, phi(j));

or

            t = t * phi(j);

Also, one can write phi[j-1] in place of phi(j).

Third, instead of

      phi(i) = (ZZX(INIT_MONO, i) - 1)/t;  

one can write

      ZZX t1;
      SetCoeff(t1, i);
      SetCoeff(t1, 0, -1);
      div(phi(i), t1, t);

Alternatively, one could directly access the coefficient vector as follows:

      ZZX t1;
      t1.SetLength(i+1); // all vector elements are initialized to zero
      t1[i] = 1;
      t1[0] = -1;
      t1.normalize();  // not necessary here, but good practice in general
      div(phi(i), t1, t);

Generally, you can freely access the coefficient vector of a polynomial, as above. However, after fiddling with this vector, you should "normalize" the polynomial, so that the leading coefficient is non-zero: this is an invariant which all routines that work with polynomials expect to hold. Of course, if you can avoid directly accessing the coefficient vector, you should do so. You can always use the SetCoeff routine above to set or change coefficients, and you can always read the value of a coefficient using the routine coeff, e.g.,

   ... f[i] == 1 ...

is equivalent to

   ... coeff(f, i) == 1 ...

except that in the latter case, a read-only reference to zero is returned if the index i is out of range. There are also special-purpose read-only access routines LeadCoeff(f) and ConstTerm(f).

NTL provides a full compliment of arithmetic operations for polynomials over the integers, in both operator and procedural form. All of the basic operations support a "promotion logic" similar to that for ZZ, except that inputs of both types long and ZZ are promoted to ZZX. See ZZX.txt for details, and see ZZXFactoring.txt for details on the polynomial factoring routines.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex4.html0000644417616742025610000006320414064716023017305 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Modular Arithmetic
[Previous] [Up] [Next]

A Tour of NTL: Examples: Modular Arithmetic


NTL also supports modular integer arithmetic. The class ZZ_p represents the integers mod p. Despite the notation, p need not in general be prime, except in situations where this is mathematically required. The classes Vec<ZZ_p> (a.k.a., vec_ZZ_p), Mat<ZZ_p> (a.k.a., mat_ZZ_p), and ZZ_pX represent vectors, matrices, and polynomials mod p, and work much the same way as the corresponding classes for ZZ.

Here is a program that reads a prime number p, and a polynomial f modulo p, and factors it.

#include <NTL/ZZ_pXFactoring.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZ p;
   cin >> p;
   ZZ_p::init(p);

   ZZ_pX f;
   cin >> f;

   Vec< Pair< ZZ_pX, long > > factors;

   CanZass(factors, f);  // calls "Cantor/Zassenhaus" algorithm

   cout << factors << "\n";
    
}

As a program is running, NTL keeps track of a "current modulus" for the class ZZ_p, which can be initialized or changed using ZZ_p::init. This must be done before any variables are declared or computations are done that depend on this modulus.

Please note that for efficiency reasons, NTL does not make any attempt to ensure that variables declared under one modulus are not used under a different one. If that happens, the behavior of a program is completely unpredictable.


Here are two more examples that illustrate the ZZ_p-related classes. The first is a vector addition routine (already supplied by NTL):

#include <NTL/ZZ_p.h>

using namespace std;
using namespace NTL;

void add(Vec<ZZ_p>& x, const Vec<ZZ_p>& a, const Vec<ZZ_p>& b)
{
   long n = a.length();
   if (b.length() != n) Error("vector add: dimension mismatch");

   x.SetLength(n);
   long i;
   for (i = 0; i < n; i++)
      add(x[i], a[i], b[i]);
}

The second example is an inner product routine (also supplied by NTL):

#include <NTL/ZZ_p.h>

using namespace std;
using namespace NTL;

void InnerProduct(ZZ_p& x, const Vec<ZZ_p>& a, const Vec<ZZ_p>& b)
{
   long n = min(a.length(), b.length());
   long i;
   ZZ accum, t;

   accum = 0;
   for (i = 0; i < n; i++) {
      mul(t, rep(a[i]), rep(b[i]));
      add(accum, accum, t);
   }

   conv(x, accum);
}

This second example illustrates two things. First, it illustrates the use of function rep which returns a read-only reference to the representation of a ZZ_p as a ZZ between 0 and p-1. Second, it illustrates a useful algorithmic technique, whereby one computes over ZZ, reducing mod p only when necessary. This reduces the number of divisions that need to be performed significantly, leading to much faster execution.

The class ZZ_p supports all the basic arithmetic operations in both operator and procedural form. All of the basic operations support a "promotion logic", promoting long to ZZ_p.

Note that the class ZZ_p is mainly useful only when you want to work with vectors, matrices, or polynomials mod p. If you just want to do some simple modular arithemtic, it is probably easier to just work with ZZ's directly. This is especially true if you want to work with many different moduli: modulus switching is supported, but it is a bit awkward.

The class ZZ_pX supports all the basic arithmetic operations in both operator and procedural form. All of the basic operations support a "promotion logic", promoting both long and ZZ_p to ZZ_pX.

See ZZ_p.txt for details on ZZ_p; see ZZ_pX.txt for details on ZZ_pX; see ZZ_pXFactoring.txt for details on the routines for factoring polynomials over ZZ_p; see vec_ZZ_p.txt for details on mathematical operations on Vec<ZZ_p>'s; see mat_ZZ_p.txt for details on mathematical operations on Mat<ZZ_p>'s.


There is a mechanism for saving and restoring a modulus, which the following example illustrates. This routine takes as input an integer polynomial and a prime, and tests if the polynomial is irreducible modulo the prime.

#include <NTL/ZZX.h>
#include <NTL/ZZ_pXFactoring.h>

using namespace std;
using namespace NTL;

long IrredTestMod(const ZZX& f, const ZZ& p)
{
   ZZ_pPush push(p); // save current modulus and install p
                     // as current modulus

   return DetIrredTest(conv<ZZ_pX>(f));

   // old modulus is restored automatically when push is destroyed
   // upon return
}

The modulus switching mechanism is actually quite a bit more general and flexible than this example illustrates.

Note the use of the conversion function conv<ZZ_pX>. We could also have used the equivalent procedural form:

   ZZ_pX f1;
   conv(f1, f);
   return DetIrredTest(f1);


Suppose in the above example that p is known in advance to be a small, single-precision prime. In this case, NTL provides a class zz_p, that acts just like ZZ_p, along with corresponding classes Vec<zz_p>, Mat<zz_p>, and zz_pX. The interfaces to all of the routines are generally identical to those for ZZ_p. However, the routines are much more efficient, in both time and space.

For small primes, the routine in the previous example could be coded as follows.

#include <NTL/ZZX.h>
#include <NTL/lzz_pXFactoring.h>

using namespace std;
using namespace NTL;

long IrredTestMod(const ZZX& f, long p)
{
   zz_pPush push(p);
   return DetIrredTest(conv<zz_pX>(f));
}


The following is a routine (essentially the same as implemented in NTL) for computing the GCD of polynomials with integer coefficients. It uses a "modular" approach: the GCDs are computed modulo small primes, and the results are combined using the Chinese Remainder Theorem (CRT). The small primes are specially chosen "FFT primes", which are of a special form that allows for particular fast polynomial arithmetic.

#include <NTL/ZZX.h>

using namespace std;
using namespace NTL;

void GCD(ZZX& d, const ZZX& a, const ZZX& b)
{
   if (a == 0) {
      d = b;
      if (LeadCoeff(d) < 0) negate(d, d);
      return;
   }

   if (b == 0) {
      d = a;
      if (LeadCoeff(d) < 0) negate(d, d);
      return;
   }

   ZZ c1, c2, c;
   ZZX f1, f2;

   content(c1, a);
   divide(f1, a, c1);

   content(c2, b);
   divide(f2, b, c2);

   GCD(c, c1, c2);

   ZZ ld;
   GCD(ld, LeadCoeff(f1), LeadCoeff(f2));

   ZZX g, res;

   ZZ prod;

   zz_pPush push; // save current modulus, restore upon return

   long FirstTime = 1;

   long i;
   for (i = 0; ;i++) {
      zz_p::FFTInit(i);
      long p = zz_p::modulus();

      if (divide(LeadCoeff(f1), p) || divide(LeadCoeff(f2), p)) continue;

      zz_pX G, F1, F2;
      zz_p  LD;

      conv(F1, f1);
      conv(F2, f2);
      conv(LD, ld);

      GCD(G, F1, F2);
      mul(G, G, LD);


      if (deg(G) == 0) {
         res = 1;
         break;
      }

      if (FirstTime || deg(G) < deg(g)) {
         prod = 1;
         g = 0;
         FirstTime = 0;
      }
      else if (deg(G) > deg(g)) {
         continue;
      }

      if (!CRT(g, prod, G)) {
         PrimitivePart(res, g);
         if (divide(f1, res) && divide(f2, res))
            break;
      }

   }

   mul(d, res, c);
   if (LeadCoeff(d) < 0) negate(d, d);
}

See lzz_p.txt for details on zz_p; see lzz_pX.txt for details on zz_pX; see lzz_pXFactoring.txt for details on the routines for factoring polynomials over zz_p; see vec_lzz_p.txt for details on vec_zz_p; see mat_lzz_p.txt for details on mat_zz_p.


NTL provides a number of "residue class" types with a dynamic modulus stored as a global variable: the types ZZ_p and zz_p, discussed above, as well as the types ZZ_pE, zz_pE, and GF2E, discussed later.

Some caution must be used so that a variable constructed under one modulus is not used "out of context", when a different modulus, or perhaps no modulus, is installed as the current modulus. While arithmetic operations should certainly be avoided, NTL does take care to allow for certain operations to be safely performed "out of context". These operations include default and copy constructors, as well as assignment.


Arithmetic mod 2 is such an important special case that NTL provides a class GF2, that acts just like ZZ_p when p == 2, along with corresponding classes Vec<GF2>, Mat<GF2>, and GF2X. The interfaces to all of the routines are generally identical to those for ZZ_p. However, the routines are much more efficient, in both time and space. Note that Vec<GF2> is an explicit specialization of the template class Vec<T>, with a special implementation that packs the coefficients into the bits of a machine word. You need to include the header file <NTL/vec_GF2.h> to use the class Vec<GF2>.

This example illustrates the GF2X and Mat<GF2> classes with a simple routine to test if a polynomial over GF(2) is irreducible using linear algebra. NTL's built-in irreducibility test is to be preferred, however.

#include <NTL/GF2X.h>
#include <NTL/mat_GF2.h>

using namespace std;
using namespace NTL;

long MatIrredTest(const GF2X& f)
{
   long n = deg(f);

   if (n <= 0) return 0;
   if (n == 1) return 1;

   if (GCD(f, diff(f)) != 1) return 0;

   Mat<GF2> M;

   M.SetDims(n, n);

   GF2X x_squared = GF2X(INIT_MONO, 2);

   GF2X g;
   g = 1;

   for (long i = 0; i < n; i++) {
      VectorCopy(M[i], g, n);
      M[i][i] += 1;
      g = (g * x_squared) % f;
   }

   long rank = gauss(M);

   if (rank == n-1)
      return 1;
   else
      return 0;
}

Note that the statement

   g = (g * x_squared) % f;

could be replace d by the more efficient code sequence

   MulByXMod(g, g, f);
   MulByXMod(g, g, f);

but this would not significantly impact the overall running time, since it is the Gaussian elimination that dominates the running time.

See GF2.txt for details on GF2; see GF2X.txt for details on GF2X; see GF2XFactoring.txt for details on the routines for factoring polynomials over GF2; see vec_GF2.txt for details on vec_GF2; see mat_GF2.txt for details on mat_GF2.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex5.html0000644417616742025610000001330514064716023017303 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Extension Rings and Fields
[Previous] [Up] [Next]

A Tour of NTL: Examples: Extension Rings and Fields


NTL also supports extension rings and fields over finite fields, and polynomial arithmetic over such extensions. Here is a little program that illustrates this.

#include <NTL/ZZ_pXFactoring.h>
#include <NTL/ZZ_pEX.h>

using namespace std;
using namespace NTL;

int main()
{
   ZZ_p::init(ZZ(17)); // define GF(17)

   ZZ_pX P;
   BuildIrred(P, 10); // generate an irreducible polynomial P
                      // of degree 10 over GF(17)

   ZZ_pE::init(P); // define GF(17^10)

   ZZ_pEX f, g, h;  // declare polynomials over GF(17^10)

   random(f, 20);  // f is a random, monic polynomial of degree 20
   SetCoeff(f, 20);

   random(h, 20); // h is a random polynomial of degree less than 20

   g = MinPolyMod(h, f); // compute the minimum polynomial of h modulo f

   if (g == 0) Error("oops (1)"); // check that g != 0

   if (CompMod(g, h, f) != 0) // check that g(h) = 0 mod f
      Error("oops (2)");
}

This example illustrates building extension rings over ZZ_p. One can also use zz_p and GF2 as base classes; the syntax is exactly the same.

See ZZ_pE.txt for the basics of the extension ring ZZ_pE over ZZ_p. Also see ZZ_pEX.txt for polynomial arithmetic over ZZ_pE, and ZZ_pEXFactoring.txt for factoring routines over ZZ_pE. See vec_ZZ_pE.txt for vectors over ZZ_pE, and mat_ZZ_pE.txt for matrices over ZZ_pE.

See lzz_pE.txt for the basics of the extension ring zz_pE over zz_p. Also see lzz_pEX.txt for polynomial arithmetic over zz_pE, and lzz_pEXFactoring.txt for factoring routines over zz_pE. See vec_lzz_pE.txt for vectors over zz_pE, and mat_lzz_pE.txt for matrices over zz_pE.

See GF2E.txt for the basics of the extension ring GF2E over GF2. Also see GF2EX.txt for polynomial arithmetic over GF2E, and GF2EXFactoring.txt for factoring routines over GF2E. See vec_GF2E.txt for vectors over GF2E, and mat_GF2E.txt for matrices over GF2E.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex6.html0000644417616742025610000000770314064716023017311 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Floating Point Classes
[Previous] [Up] [Next]

A Tour of NTL: Examples: Floating Point Classes


NTL also supports arbitrary precision floating point with the class RR. Additionally, it supports two specialized classes: quad_float, which gives a form of quadruple precision, but without an extended exponent range, and xdouble, which gives double precision, but with an extended exponent range. The advantage of the latter two classes is efficiency.

Here again is a program that reads a list of numbers from the input, and outputs the sum of their squares, using the class RR.

#include <NTL/RR.h>

using namespace std;
using namespace NTL;

int main()
{
   RR acc, val;

   acc = 0;
   while (cin >> val)
      acc += val*val;

   cout << acc << "\n";
}

The precision used for the computation can be set by executing

   RR::SetPrecision(p);

which sets the effective precision to p bits. By default, p=150. All of the basic arithmetic operations compute their results by rounding to the nearest p-bit floating point number. The semantics of this are exactly the same as in the IEEE floating point standard (except that there are no special values, like "infinity" and "not a number").

The number of decimal digits of precision that are used when printing an RR can be set be executing

   RR::SetOutputPrecision(d);

which sets the output precision to d. By default, d=10.

See RR.txt for details.

By replacing the occurences of RR by either quad_float or xdouble, one gets an equivalent program using one of the other floating point classes. The output precision for these two classes can be controlled just as with RR. See quad_float.txt and xdouble.txt for details.

[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-ex7.html0000644417616742025610000001560414064716023017311 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Examples: Thread Pools
[Previous] [Up] [Next]

A Tour of NTL: Examples: Thread Pools


If you have built NTL with NTL_THREAD_BOOST=on, then not only is NTL thread safe, but certain parts of NTL are designed to use multiple threads to speed things up. To implement this, NTL makes use of a thread pool, which is a collection of threads that are created once and then used over and over again, to avoid the significant overhead of thread creation and destruction. You can also use this same thread pool to speed up NTL client code.

To use this feature, you have to include the header file NTL/BasicThreadPool.h. In your main program, you should also indicate how many threads you want in the pool. If you want, say, 8 threads, you so this by calling the function SetNumThreads(8).

If you do this, then certain parts of NTL will use these threads when possible (this is a working in progress). To use these threads in your own code, the easiest way to do this is with a parallel for loop, illustrated in the following example. See BasicThreadPool.txt for more details. Consider the following routine:

   void mul(ZZ *x, const ZZ *a, const ZZ *b, long n)
   {
      for (long i = 0; i < n; i++)
         mul(x[i], a[i], b[i]);
   }

We can parallelize it as follows:

   void mul(ZZ *x, const ZZ *a, const ZZ *b, long n)
   {
      NTL_EXEC_RANGE(n, first, last)

         for (long i = first; i < last; i++)
            mul(x[i], a[i], b[i]);

      NTL_EXEC_RANGE_END
   }

NTL_EXEC_RANGE and NTL_EXEC_RANGE_END are macros that just do the right thing. If there are nt threads available, the interval [0..n) will be partitioned into (up to) nt subintervals, and a different thread will be used to process each subinterval. You still have to write the for loop yourself: the macro just declares and initializes variables first and last (or whatever you want to call them) of type long that represent the subinterval [first..last) to be processed by one thread.

Note that the current thread participates as one of the nt available threads, and that the current thread will wait for all participating threads to finish their task before proceeding.

Withing the "body" of this construct, you can freely reference any variables that are visible at this point. This is implemented using the C++ lambda feature (capturing all variables by reference).

This construct will still work even if threads are disabled, in which case it runs single-threaded with first=0 and last=n.

Note that the code within the EXEC_RANGE body could call other routines that themselves attempt to execute an EXEC_RANGE: if this happens, the latter EXEC_RANGE will detect this and run single-threaded.

You may wish to do other things within the EXEC_RANGE body than just execute a loop. One thing you may want to do is to declare variables. Another thing you may want to do is setup a local context for a ZZ_p modulus (or other type of modulus). Here is an example of doing this:

   void mul(ZZ_p *x, const ZZ_p *a, const ZZ_p *b, long n)
   {
      ZZ_pContext context;
      context.save();

      NTL_EXEC_RANGE(n, first, last)
      
         context.restore();

         for (long i = first; i < last; i++)
            mul(x[i], a[i], b[i]);

      NTL_EXEC_RANGE_END
   }

A lower-level set of tools is available, which allow for more fine-grained control. See BasicThreadPool.txt for more details.

[Previous] [Up] [Next]
ntl-11.5.1/doc/arrow1.gif0000644417616742025610000000170714064716023016632 0ustar gid-shoupvpug-gid-shoupvGIF89a22p*5+7+7,8,9-:.;/0<2>0=0>5A8D4A5B:F:F7D9FJ@@BLBMHSJUPZS]U_BOEQJUFRFSS^Q]Xb_hWa`i`iclcmdnnvJWMZMZQ^R_UaS`@`UbWdZfYfr{ano{{w~z|֎ڕڛފᒙ瀀៥ဠ᦬﫱顫! ,22om_ij\X--! -0O_m\0 (0iO!ò&&0XjO±Mak\&7MMQ_O3qDl@hݰ " 6CW;XhJƓ7i]xR苆8S`wA3o H5@E .?k1(̀HyxM..`rd.XqnhKhVܾCѴ}wooZ% E͓1xɛgr]XfΎ1>0=0>1>6A:E9E?J4A3@6B:FJ3@5B9F>J=J0=0>1>7C9E:F3@3@5B>J9F=I;H=J:G;H=J=J?LBM@KPZQ[ANEQFRCPLXR]R]@`\e_hW`Wa_h]g`i`iltmucldndnirJVVc@`_leokwmzz{Հڏݕݖᥫ㫰벷冀! ,22igWP66PWciWF2296FXg_õ __CӶ99GJ`cD 9;GGYWŸJ͌P՛v uYAa2╻ .(k<(bģ75l %@R)$Eeb qrX@c]!Hp )Df#φ8*N{aQy2*gU'H)h'WR#EZl !g}tJli 4$nh04Hp3BȊ_hޜS`0 %#.S&{3^aJܼ`ـsz3,r1,s\\:d{)흻΋Y^>."otp@Ct}p`t*8VJ!`P݅v ($h≂!((c)1998 DeMorgan Industries CorpUSSPCMT! PIANYGIF1.0Image;ntl-11.5.1/doc/tour-gmp.html0000644417616742025610000002060114064716023017362 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Using NTL with GMP
[Previous] [Up] [Next]

A Tour of NTL: Using NTL with GMP


GMP is the GNU Multi-Precision library. You can get more information about it, as well as the latest version from here.

Briefly, GMP is a library for long integer arithmetic. It has hand-crafted assembly routines for a wide variety of architectures. For basic operations, like integer multiplication, it can be two to three (and sometimes bit more) times faster than NTL's traditional long integer package. The speedup is most dramatic on x86 machines.

As of version 9.6.3, NTL uses GMP by default. You can disable GMP by passing NTL_GMP_LIP=off as an option to NTL's configure script. If you disable the use of GMP, NTL uses a long integer package derived from Arjen Lenstra's LIP package. This is not recommended: GMP is much faster.

Even if you do not use GMP, you should still read the section below on backward compatabilty so that you can write portable code and avoid deprecated constructs.

Note: GMP is thread safe, so you should feel free to use it in a thread-safe build of NTL. However, the current version of GMP (v6.1) is not entirely exception friendly (it may abort a running program, but only in some very extreme and unusal circumstances).

Downloading and building GMP

Many unix distributions now include GMP by default. But if not, it is pretty easy to install it directly from source, as follows.

Download GMP from here. You will get a file gmp-XXX.tar.gz.

Now do the following:

   % gunzip gmp-XXX.tar.gz
   % tar xf gmp-XXX.tar
   % cd gmp-XXX
   % ./configure --prefix=$HOME/sw
   % make
   % make check
   % make install
This will build, test, and install GMP in $HOME/sw. Of course, change $HOME/sw to whatever you want (the default is /usr/local). You will find the GMP header files in $HOME/sw/include and the compiled binaries in $HOME/sw/lib.

You can also supply the option --disable-shared to the configure script, if you only want static libraries. However, if you ultimately want to build NTL as a shared library, then you must also buld GMP as a shared library.

You must ensure that NTL and GMP have the same ABI. Usually, GMP's configure script will automatically choose a 64-bit ABI if available.

Building and using NTL with GMP

When you are installing NTL, if you installed GMP in $HOME/sw as above, and you also want to install NTL in $HOME/sw, you execute:

   % ./configure PREFIX=$HOME/sw GMP_PREFIX=$HOME/sw
You can write this more simply as
   % ./configure DEF_PREFIX=$HOME/sw 
Here, DEF_PREFIX is a variable that is used to specify the location of all software, and it defaults to /usr/local.

If you installed GMP in /usr/local (or some other standard system directory where your compiler will look by default) then simply

   % ./configure PREFIX=$HOME/sw 
does the job. Moreover, if NTL is also to be installed in /usr/local, then
   % ./configure 
does the job.

When compiling programs that use NTL with GMP, you need to link with the GMP library. If GMP is installed as above in $HOME/sw, rather than in a standard system directory, this just means adding -L$HOME/sw/lib -lgmp to the compilation command. If you installed GMP in a standard system directory, then just -lgmp does the job. Note that -lgmp must come after -lntl on the command line. Finally, if NTL and GMP are installed as shared libraries, then you don't even need -lgmp.

NTL has been tested and works correctly with GMP versions 3.1, 3.1.1, 4.1.4, 5.1, 6.0, and 6.1 (among others). It is not possible to use versions of GMP prior to 3.1 with NTL.

When using NTL with GMP, as a user of NTL, you do not need to know or understand anything about the the GMP library. So while there is detailed documentation available about how to use GMP, you do not have to read it. The programming interface to the long integer package completely hides implementation details.

Backward compatbility

With version 5.0 of NTL, some aspects of the programming interface are 'deprecated' so as to allow the use of another long integer package, such as GMP, as the long integer package.

Prior to version 5.0, the macro NTL_NBITS was defined, along with the macro NTL_RADIX defined to be (1L << NTL_NBITS). While these macros are still available when using NTL's traditional long integer package (i.e., when NTL_GMP_LIP is not set), they are not available when using the GMP as the long integer package (i.e., when NTL_GMP_LIP is set). Furthermore, when writing portable programs, one should avoid these macros.

Also, the static function long ZZ::digit(const ZZ &, long); is defined when using traditional long integer arithmetic, but is not available when using GMP as the long integer package, and in any case, its use should be avoided when writing portable programs.

Instead of the above macros, one should use the followng macros:

   NTL_ZZ_NBITS -- number of bits in a limb;
                   a ZZ is represented as a sequence of limbs.

   NTL_SP_NBITS -- max number of bits in a "single-precision" number

   NTL_WSP_NBITS -- max number of bits in a "wide single-precision" number

The following relations hold:

   NTL_SP_NBITS <= NTL_WSP_NBITS <= NTL_ZZ_NBITS
   26 <= NTL_SP_NBITS <= min(NTL_BITS_PER_LONG-2, NTL_DOUBLE_PRECISION-3)
   NTL_WSP_NBITS <= NTL_BITS_PER_LONG-2

Note that NTL_ZZ_NBITS may be less than, equal to, or greater than NTL_BITS_PER_LONG -- no particular relationship should be assumed to hold. In particular, expressions like (1L << NTL_ZZ_BITS) might overflow.

"single-precision" numbers are meant to be used in conjunction with the single-precision modular arithmetic routines.

"wide single-precision" numbers are meant to be used in conjunction with the ZZ arithmetic routines for optimal efficiency.

Note that when using traditional long integer arithmetic, we have

    NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS.

The following auxilliary macros are also defined:

NTL_FRADIX -- double-precision value of 2^NTL_ZZ_NBITS
NTL_SP_BOUND -- (1L << NTL_SP_NBITS)
NTL_WSP_BOUND -- (1L << NTL_WSP_NBITS)

Note that for a ZZ n, n.size() returns the number of "limbs" of n. This is supported with either traditional or GMP integer arithemtic. Note, however, that some old codes might write n.size() <= 1 as a way to test if NumBits(n) <= NTL_NBITS. This is no longer the right thing to do, if one wants portable code that works with either traditional or GMP long integer arithmetic. First, one has to decide whether one wants to test if NumBits(n) is bounded by NTL_ZZ_NBITS, NTL_SP_NBITS, or NTL_WSP_NBITS. In the first case, n.size() <= 1 is still the right way to test this. In the second case, write this as n.SinglePrecision(). In the third case, write this as n.WideSinglePrecision(). The routines SinglePrecision and WideSinglePrecision are new to NTL version 5.0.

Most "high level" applications that use NTL should not be affected by these changes to NTL's programming interface, and if they are, changing the programs should be quite easy.


[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-gf2x.html0000644417616742025610000001067214064716023017454 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Using NTL with the gf2x library
[Previous] [Up] [Next]

A Tour of NTL: Using NTL with the GF2X library


gf2x is a library for fast multiplication of polynomials over GF(2). The gf2x library was developed by Emmanuel Thomé, Paul Zimmermmann, Pierrick Gaudry, and Richard Brent. You can get more information about it, as well as the latest version from here.

Unlike NTL, which only imlements a version of Karatsuba multiplication, gf2x implements other algorithms that are faster for very large degree polynomials. If you use NTL if the gf2x library, then multiplication, division, GCD, and minimum polynomal calculations for the GF2X class will be faster for large degree polymials.

Note: you will need version 1.2 or later of gf2x for a thread-safe build of NTL.

Downloading and building gf2x

Download gf2x from here. You will get a file gf2x-XXX.tar.gz.

Now do the following:

   % gunzip gf2x-XXX.tar.gz
   % tar xf gf2x-XXX.tar
   % cd gf2x-XXX
   % ./configure --prefix=$HOME/sw
   % make
   % make check
   % make install
This will build, test, and install gf2x in $HOME/sw. Of course, change $HOME/sw to whatever you want (the default is /usr/local). You will find the gf2x header files in $HOME/sw/include and the compiled binaries in $HOME/sw/lib.

You can also supply the option --disable-shared to the configure script, if you only want static libraries. However, if you ultimately want to build NTL as a shared library, then you must also build gf2x as a shared library.

You must ensure that NTL and gf2x have the same ABI. gf2x's configuration script might need some help to select the right one. For example, you may have to pass

   ABI=64 CFLAGS="-m64 -O2"
to gf2x's configure script to force a 64-bit ABI.

Building and using NTL with gf2x

When building NTL with gf2x, you have to tell NTL that you want to use it. The easiest way to do this is by passing the argument NTL_GF2X_LIB=on to the NTL configuration script when you are installing NTL. Assuming you installed gf2x in $HOME/sw as above, and you also want to install NTL in $HOME/sw, you execute:

   % ./configure PREFIX=$HOME/sw NTL_GF2X_LIB=on  GF2X_PREFIX=$HOME/sw
You can write this more simply as
   % ./configure DEF_PREFIX=$HOME/sw NTL_GF2X_LIB=on 
Here, DEF_PREFIX is a variable that is used to specify the location of all software, and it defaults to /usr/local.

If you installed gf2x in /usr/local (or some other standard system directory where your compiler will look by default) then simply

   % ./configure PREFIX=$HOME/sw NTL_GF2X_LIB=on
does the job. Moreover, if NTL is also to be installed in /usr/local, then
   % ./configure NTL_GF2X_LIB=on
does the job.

When compiling programs that use NTL with gf2x, you need to link with the gf2x library. If gf2x is installed as above in $HOME/sw, rather than in a standard system directory, this just means adding -L$HOME/sw/lib -lgf2x to the compilation command. If you installed gf2x in a standard system directory, then just -lgf2x does the job. Note that -lgf2x must come after -lntl on the command line. Finally, if NTL and gf2x are installed as shared libraries, then you don't even need -lgf2x.


[Previous] [Up] [Next]
ntl-11.5.1/doc/tour-tips.html0000644417616742025610000000703514064716023017564 0ustar gid-shoupvpug-gid-shoupv A Tour of NTL: Tips for Getting the Best Performance out of NTL
[Previous] [Up] [Next]

A Tour of NTL: Tips for Getting the Best Performance out of NTL


  1. Make sure you run the configuration wizard when you install NTL. This is the default behaviour in the makefile in the Unix distribution, so don't change this; in the Windows distribution, there is unfortunately no easy way to run the wizard.

  2. In time-critical code, avoid creating unnecessary temporary objects. For example, instead of

    ZZ InnerProduct(const ZZ *a, const ZZ *b, long n)
    {
       long i;
       ZZ res;
       for (i = 0; i < n; i++)
          res += a[i] * b[i];
       return res;
    }

    write this as

    ZZ InnerProduct(const ZZ *a, const ZZ *b, long n)
    {
       long i;
       ZZ res, t;
       for (i = 0; i < n; i++) {
          mul(t, a[i], b[i]);
          add(res, res, t);
       }
       return res;
    }

    The first version of InnerProduct creates and destroys a temporary object, holding the value a[i]*b[i], in every loop iteration. The second does not.

  3. If you use the class ZZ_p, try to avoid switching the modulus too often, as this can be a rather expensive operation. If you must switch the modulus often, use the class ZZ_pContext to save the information associated with the modulus (see ZZ_p.txt). The same holds for analogous classes, such as zz_p and GF2E.

[Previous] [Up] [Next]
ntl-11.5.1/doc/config.txt0000644417616742025610000005673614064716023016752 0ustar gid-shoupvpug-gid-shoupv usage: ./configure [ variable=value ]... This configure script generates the file 'makefile' and the file '../include/NTL/config.h', based upon the values assigned to the variables on the command line. ########### Here are the most important variables, and their default values. CXX=g++ # The C++ compiler CXXFLAGS=-g -O2 # C++ complilation flags NATIVE=on # compiles code targeted to current hardware TUNE=generic # performance-tuning switch (or x86 or linux-s390x) DEF_PREFIX=/usr/local# Default software directory PREFIX=$(DEF_PREFIX) # Directory in which to install NTL library components SHARED=off # Generate a shared library (as well as static) NTL_THREADS=on # compile in thread-safe mode NTL_THREAD_BOOST=on # compile with thread boosting enabled NTL_EXCEPTIONS=off # compile in exception-safe mode NTL_GMP_LIP=on # Switch to enable the use of GMP as primary # long integer package GMP_PREFIX=$(DEF_PREFIX) # Directory in which GMP components are installed NTL_GF2X_LIB=off # Switch to enable the use of the gf2x package # for faster arithmetic over GF(2)[X] GF2X_PREFIX=$(DEF_PREFIX) # Directory in which gf2x components are installed NTL_STD_CXX11=on # Build assuming C++11 features NTL_SAFE_VECTORS=on # build in "safe vector" mode NTL_ENABLE_AVX_FFT=off # implement the small-prime FFT using AVX # instructions...this is experimental at # moment, and may lead to worse performance NTL_AVOID_AVX512=off # avoid using 512-bit AVX registers NTL_RANDOM_AES256CTR=off # implement pseudorandom generator using AES-256-CTR ########## Here are more detailed description of these variables. ########## Basic compilation variables: CXX=g++ # A C++ compiler, e.g., g++, CC, xlC CXXFLAGS=-g -O2 # Flags for the C++ compiler. # It is highly recommend to avoid things like -O3 and -Ofast. # These may yield incorrect code. NATIVE=on # Flag to target code to current hardware. Setting this flag will pass # -march=native through to the compiler via CXXAUTOFLAGS (if possible). This # is the easiest way to exploit the hardware capabilities of your machine to # their fullest potential. Note that if CXXFLAGS contains an '-march=XXX' # option, then NATIVE will be turned off. TUNE=generic (or x86 or linux-s390x) # Switch to determine how various performance options get set # auto make runs a performance-tuning wizard # generic should be OK for most platforms # x86 should be well suited for most x86 platforms # linux-s390x should be well suited for Linux on IBM Z platforms from z15 onward # More choices may be added in the future. # Right now, the default is # - x86, if configure detects that is is running on an x86 platform, # - linux-s390x, if configure detects that it is running on Linux on an IBM Z platform # and the compiler is either gcc or clang, and # - generic, otherwise. ########## Installation path: DEF_PREFIX=/usr/local # Default software directory PREFIX=$(DEF_PREFIX) # Set this to the directory in which you want NTL components to be installed. # When 'make install' is executed, the header files are copied into # $(PREFIX)/include/NTL, the library itself is copied to # $(PREFIX)/lib/libntl.a, and the documentation files are copied into # $(PREFIX)/share/doc/NTL. Unless you have root permissions when running 'make # install', you will have to override the default PREFIX value with the name of # your own local directory. If you want finer-grained control over where the # different library components are installed, set the variables INCLUDEDIR, # LIBDIR, and DOCDIR (see below). ########## Shared library switch: SHARED=off # Set this to 'on' if you want to generate a shared library, in addition to a # static library. Shared libraries have many advantages, but unfortunately, # their use is rather less portable than that of good, old-fashioned static # libraries. If you set SHARED=on, then the makefile will use a libtool # script. By default, the libtool script used is freshly built when you run # configure. This libtool script is built using another configure sctipt. # Currently, you can't pass any arguments to this configure script (but you can # communicate with it via environment variables, as usual). # # You can use a pre-built libtool command by setting the configuration variable # LIBTOOL. You can also build a custom libtool script by running the configure # script in the subdirectory libtool-origin with specialized arguments. # # Note that if SHARED=on, then in addition to using the libtool # program, the makefile relies on features specific to GNU make. ########## thread safety NTL_THREADS=on # Set to 'on' if you want to compile NTL in thread-safe mode. This requires # several C++11 features, including atomic types, mutexes, and thread_local # storage. Your compiler may not yet support these features. Setting this # flag will automatically set the NTL_STD_CXX11 flag (if neither NTL_STD_CXX11 # or NTL_STD_CXX14 is already set). It will also pass -pthread throught to the # compiler via CXXAUTOFLAGS (if possible). # # Turning this flag off will also turn off the NTL_THREAD_BOOST flag. ########## thread boosting NTL_THREAD_BOOST=on # Set to 'on' if you want to compile NTL so that is does certain internal # computations using multiple threads. # # This feature is a work in progress. As time goes on, more NTL algorithms are # thread boosted. See BasicThreadPool documentation file for more details. ########## exceptions NTL_EXCEPTIONS=off # Set to 'on' if you want to compile NTL with exceptions enabled. This # requires several C++11 features, including lambdas and the new rules for # exception specifications. Your compiler may not yet support these feautures. # Setting this flag will automatically set the NTL_STD_CXX11 flag (if neither # NTL_STD_CXX11 or NTL_STD_CXX14 is already set). # With exceptions disabled, any error conditions detected by NTL (including # memory allocation errors) will result in an error message and a call to # abort. Also, if compiling in C++11 mode (or later, see NTL_STD_CXX11), with # exceptions disabled, certain move constructors and move assignment operators # will be declared "noexcept". This can lead to greater efficiency (for # example, std::vector's take advantage of this to avoid call to copy # contructors). # With exceptions enabled, most error conditions detected by NTL will result in # an exception being thrown. NTL will also be compiled in a "thread safe" mode # that prevents memory leaks (and other problems). In addition, some move # constructors and move assignment operators may not be declared "noexcept". ########## GMP variables: NTL_GMP_LIP=on # Set to 'off' if you don't want to use GMP, the GNU Multi-Precision package, # as the primary long integer package. This will lead to significantly slower # code, and is not recommended. GMP_PREFIX=$(DEF_PREFIX) # If GMP was installed in a standard system directory, e.g., /usr/local, then # do not set this variable. Otherwise, if you want to use GMP and GMP was # installed in a directory , then set GMP_PREFIX=. # This works if the directory /include contains gmp.h and # /lib contains libgmp.a. For finer-grained control, set the # variables GMP_INCDIR and GMP_LIBDIR instead (see below). ########## GF2X variables: NTL_GF2X_LIB=off # Set to 'on' if you want to use the gf2x library for faster arithmetic over # GF(2)[X] (the NTL class GF2X). # If you set this flag, please note the following. If you have installed gf2x # in a standard "system" location, this is all you have to do. Otherwise, if # gf2x is built, but not installed in a standard place, you have to set the # variable GF2X_PREFIX. GF2X_PREFIX=$(DEF_PREFIX) # If gf2x was installed in a standard system directory, e.g., /usr/local, then # do not set this variable. Otherwise, if you want to use gf2x and gf2x was # installed in a directory , then set GF2X_PREFIX=. # This works if the directory /include contains gf2x.h and # /lib contains libgf2x.a. For finer-grained control, set the # variables GF2X_INCDIR and GF2X_LIBDIR instead (see below). ########### Language stadards NTL_STD_CXX11=on # Build assuming C++11 features NTL_STD_CXX14=off # Build assuming C++14 features # Setting one of these may also result in passing pass either -std=c++11 or # -std=c++14 through to the compiler via CXXAUTOFLAGS (if it is necessary and # possible). ############ Safe vector mode NTL_SAFE_VECTORS=on # Build in "safe vector mode" # Build NTL in "safe vector mode", which relaxes the "relocatability" # requirement for NTL vector types. I expect that at some point in the next # couple of years, this will be "on" by default. Setting this flag will # automatically set the NTL_STD_CXX11 flag (if neither NTL_STD_CXX11 or # NTL_STD_CXX14 is already set). See vector documentation file for more # details. ############ AVX FFT NTL_ENABLE_AVX_FFT=off # implement the small-prime FFT using AVX # instructions...this is experimental at # moment, and may lead to worse performance On machines with AVX2/FMA or AVX512, this will implement the small-prime FFT using AVX code. This is still quite experimental, and may lead to worse performance. While the FFT itself can run 2-3 times faster, this comes at the cost of (1) restriction to 50-bit primes (so NTL_SP_NBITS will be set to 50 instead of 60), and (2) the CPU speed may be throttled, slowing down other operations. So far, it seems that the only operations that are faster are arithmetic operations in zz_pX, and only for certain choices of modulus. Arithmetic operations in ZZ_pX, with large modulus, can run slower with AVX than without. ########### Avoid 512-bit AVX registers NTL_AVOID_AVX512=off # avoid using 512-bit AVX registers Even if available, this will avoid the use of 512-bit AVX registers. This affects both Mat operations, as well as the AVX-based FFT (see above). ########### Use AES-256-CTR based pseudorandom generator NTL_RANDOM_AES256CTR=off # implement pseudorandom generator using AES-256-CTR AES-256-CTR based pseudorandom generation may be faster than the default in case AES instruction set extensions are available on the processor and supported by the implementations. The implementation supports the following AES instruction set extensions if detected at build time: x86 : AES-NI linux-s390x : KMA Be aware of possible interoperability issues when changing the implementation of NTL's pseudorandom generator object. ########### Examples: # If you are happy with all the default values: ./configure # If your C++ compiler is called icpc: ./configure CXX=icpc # If GMP was installed in a non-standard directory, say, $HOME/sw: ./configure GMP_PREFIX=$HOME/sw # If you want to use the options -g and -O for compiling C++, # just execute ./configure "CXXFLAGS=-g -O" # Note the use of quotes to keep the argument in one piece. # If you want to use the gf2x library: ./configure NTL_GF2X_LIB=on ########### ########### A little magic ########### CXXAUTOFLAGS= # This is a variable that is automagically set by the configuration script. # These are C++ compiler flags that are selected depending on the choice of # other configuration options, as well as information gleaned by the # configuration script about the compiler. To do this, the configuration # script attempts to figure out the type of compiler and the default language # standard supported. The types of compiler currently recognized are gcc, # clang, and icc. For these compilers, the automagic should definitely work. # For others, your mileage may vary. The configuration script always prints # out the value it chooses. Currently, the following flags may get passed # through CXXAUTOFLAGS: # # -std=c++11 # -std=c++14 if requested explicitly via NTL_STD_CXX11=on or # NTL_STD_CXX14=on, or implicitly via a request # for a feature that requires C++11 # # -pthread if thread-safety is requested via NTL_THREADS=on # or NTL_THREAD_BOOST=on # # -fp-model precise only for the Intel icc compiler (to prevent # non-value-preserving floating point optimizations) # # If you explicitly set the value of CXXAUTOFLAGS when invoking the # configuration script, then it will not change that value. NOCONTRACT= # Like the CXXAUTOFLAGS variable, this is set automagically by the # configuration script, unless you explicitly provide a value. It is only used # in compiling the source files that implement the quad_float class and the AVX # FFT. For these files only, NTL requires not only that the compiler does not # perform any non-value-preserving floating point optimizations, but that is # also does not perform any "contractions" (i.e., emit FMA (fused multiply add) # instructions. Currently, it may be set as follows: # # -ffp-contract=off for gcc (and possibly clang) compilers # # -mno-fused-madd for old gcc compilers that don't support # -ffp-contract=off # -DFP_CONTRACT_OFF for the Intel icc compiler # # The configuation script will make every attempt to ensure that this really # does disable contractions. If it doesn't work, a fallback strategy is used # that should still work (but with a performance penalty). MAKE_PROG=make # To set CXXAUTOFLAGS and NOCONTRACT, the configure script actually needs to # run make. If you wish to use a non-standard make program for this purpose, # set this variable to point to that program. ########### Here is a complete list of the remaining variables, ########### with their default values. These variables are pretty ########### esoteric, and you will probably never change their ########### default values. AR=ar ARFLAGS=ruv RANLIB=ranlib LDFLAGS= LDLIBS=-lm CPPFLAGS= LIBTOOL=undefined LIBTOOL_LINK_FLAGS= LIBTOOL_LINK_LIBS=undefined LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc NTL_TLS_HACK=on NTL_DISABLE_MOVE_ASSIGN=on NTL_DISABLE_MOVE=off NTL_LEGACY_NO_NAMESPACE=off NTL_LEGACY_INPUT_ERROR=off NTL_LEGACY_SP_MULMOD=off NTL_UNSIGNED_LONG_LONG_TYPE=undefined NTL_CLEAN_INT=off NTL_CLEAN_PTR=on NTL_RANGE_CHECK=off NTL_X86_FIX=off NTL_NO_X86_FIX=off NTL_NO_INIT_TRANS=on NTL_DISABLE_LONGDOUBLE=off NTL_DISABLE_LONGLONG=off NTL_DISABLE_LL_ASM=off NTL_MAXIMIZE_SP_NBITS=off NTL_SPMM_ULL=off NTL_FFT_BIGTAB=off NTL_FFT_LAZYMUL=off NTL_TBL_REM=off NTL_AVOID_BRANCHING=off NTL_GF2X_NOINLINE=off NTL_GF2X_ALTCODE=off NTL_GF2X_ALTCODE1=off GMP_INCDIR=$(GMP_PREFIX)/include GMP_LIBDIR=$(GMP_PREFIX)/lib GF2X_INCDIR=$(GF2X_PREFIX)/include GF2X_LIBDIR=$(GF2X_PREFIX)/lib ########### Here is a more detailed description of these variables. ########### Further compilation variables: AR=ar # command to make a library ARFLAGS=ruv # arguments for AR RANLIB=ranlib # set to echo if you want to disable it completely LDFLAGS= # arguments for linker for C++ programs LDLIBS=-lm # libraries for linking C++ programs CPPFLAGS= # arguments for the C preprocessor LIBTOOL=undefined # the libtool command -- only needed if SHARED=on # if left undefined, a fresh libtool script will be built LIBTOOL_LINK_FLAGS= # flags to add to command line when building a shared library # mainly used to pass the argument "-no-undefined" on cygwin LIBTOOL_LINK_LIBS=undefined # libraries to add to the command line when building a shared library. # mainly used to pass the argument "-lpthread", which NTL's # configure script will do automatically if SHARED=on and NTL_THREADS=on, # unless user explicitly provides a value for LIBTOOL_LINK_LIBS. # the purpose of this is to prevent so-called "underlinking". # specifically, it allows NTL clients to not pass "-pthread" to the # compiler when linking their own programs. ########### Details of the compilation process (when SHARED=off) # When a C++ file foo.c is compiled: $(CXX) -I../include $(CPPFLAGS) $(CXXFLAGS) -c foo.c # When a C++ file foo.c is compiled and linked: $(CXX) -I../include $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) \ -o foo foo.c $(LDLIBS) # When the library ntl.a is built $(AR) $(ARFLAGS) ntl.a [ object files ]... $(RANLIB) ntl.a # If the ranlib command does not exist, everything will still function OK. ########### Further installation variables: LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include DOCDIR=$(PREFIX)/share/doc # Where to install NTL. # # Execution of 'make install' copies header files into $(INCLUDEDIR)/NTL, # copies the library itself to $(LIBDIR)/libntl.a, and copies the documentation # files into $(DOCDIR)/NTL. ########## TLS hack NTL_TLS_HACK=on # when building NTL with NTL_THREADS=on, if the compiler is gcc-compatible, a # "TLS hack" may be used to workaround the fact that many compilers do not # (correctly) implement C++11's thread_local feature. The workaround is to use # gcc's more limited __thread feature, and to emulate thread_local semantics # using pthread routines. # # The configuration script will first check if threads and TLS work with the # hack, and if not, will try setting NTL_TLS_HACK=off. You can also turn off # the hack by setting NTL_TLS_HACK=off. ########## Disabling move semantics NTL_DISABLE_MOVE_ASSIGN=on NTL_DISABLE_MOVE=off # The first flag will disable the generation of move assignment operators for # Vec, Mat, vec_GF2, and GF2X. By implication, move assignment operators # will be disabled as well for many other types (like polynomials). The second # flag will disable move constuctors and move assignment operators for all NTL # types. # These flags are only relevant in C++11 mode. They are meant to deal with # backward compatibility issues for legacy NTL clients that may not deal well # with automatically generated move operations. It turns out that move # semantics can quietly break programs. See # http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3153.htm # However, the default now is just to disable move assignment operators for # those classes where it seems likeliest to cause a problem. This default will # likely be changed in the future, so that no move operations are disabled. ########## Legacy switches NTL_LEGACY_NO_NAMESPACE=off # put NTL components in the global namespace NTL_LEGACY_INPUT_ERROR=off # abort on input errors, instead of just setting the # "fail bit" of the istream object NTL_LEGACY_SP_MULMOD=off # use pre-9.0 interfaces for single-precision MulMod routines. # See discussion in ZZ.txt for details. ########### Basic Configuration Options: NTL_UNSIGNED_LONG_LONG_TYPE=undefined # Name of double-word unsigned integer type. This is a non-standard type, and # is called 'long long' by many compilers. MS C++ calls it 'unsigned __int64'. # # Note that the new C99 standard defines the type 'unsigned long long' to be at # least 64-bits wide. On 32-bit machines, this is just right. Although not # officially part of the C++ standard (which predates C99), it is widely # supported by C++ compilers, and is likely to be added to the C++ standard. # # Unfortunately, 64-bit machines usually define 'unsigned long long' to also be # 64-bits wide, which is kind of useless. However, GCC provides a type # __uint128_t which does the job. # # If left undefined, NTL will use some "ifdef magic" to find the type most # suitable for your machine (based on compiler and word size). NTL_CLEAN_INT=off # Setting this to 'on' disables the use of some non-standard integer arithmetic # which would yield slightly better performance. NTL_CLEAN_PTR=on # Setting this to 'on' disables the use of some non-standard pointer arithmetic # which would yield slightly better performance. The 'off' setting really just # invites undefined behavior without any measurable performance benefit. NTL_RANGE_CHECK=off # Setting this to 'on' will generate vector subscript range-check code. Useful # for debugging, but it slows things down of course. NTL_X86_FIX=off # Set to 'on' to force the "x86 floating point fix", overriding the default # behavior. By default, NTL will apply the "fix" if it looks like it is # necessary, and if it knows how to fix it. The problem addressed here is that # x86 processors sometimes run in a mode where FP registers have more precision # than doubles. This will cause code in quad_float.c some trouble. NTL can # normally automatically detect the problem, and fix it, so you shouldn't need # to worry about this or the next flag. NTL_NO_X86_FIX=off # Set to 'on' to forces no "x86 floating point fix", overriding the default # behavior. NTL_NO_INIT_TRANS=on # When 'off', NTL uses a special code sequence to avoid copying large objects # in return statements. However, if your compiler optimizes away the return of # a *named* local object, this is not necessary, and setting this flag to 'on' # will result in *slightly* more compact and efficient code. The C++ standard # explicitly allows compilers to perform this optimization, and with time, more # compilers actually do this. Traditionally, however, most will only avoid # copying *temporary* objects in return statements, and NTL's default code # sequence exploits this fact. NTL_DISABLE_LONGDOUBLE=off # Explicitly disables use of long double arithmetic NTL_DISABLE_LONGLONG=off # Explicitly disables use of long long arithmetic NTL_DISABLE_LL_ASM=off # Explicitly disables use of inline asm as replacement for # long long arithmetic NTL_MAXIMIZE_SP_NBITS=on # Allows for 62-bit single-precision moduli on 64-bit platforms. By default, # such moduli are restricted to 60 bits, which usually gives *slightly* better # performance across a range of of parameters. ########## Performance Options: NTL_SPMM_ULL=off # Implement the MulModPrecon code using "unsigned long long" (or specify # NTL_UNSIGNED_LONG_LONG_TYPE to override the default). NTL_FFT_BIGTAB=off # Precomputed tables are used to store all the roots of unity used in FFT # computations. NTL_FFT_LAZYMUL=off # When set, a "lazy multiplication" strategy due to David Harvey: see his paper # "FASTER ARITHMETIC FOR NUMBER-THEORETIC TRANSFORMS". NTL_TBL_REM=off # With this flag, some divisions are avoided in the ZZ_pX multiplication # routines. NTL_AVOID_BRANCHING=off # With this option, branches are replaced at several key points with equivalent # code using shifts and masks. Recommended for use with RISC architectures, # especially ones with deep pipelines and high branch penalities. Newer x86 # platforms that use conditional move intrictions are slightly faster without # this option. When in doubt, turn this option on. NTL_GF2X_NOINLINE=off # By default, the low-level GF2X multiplication routine in inlined. This can # potentially lead to some trouble on some platforms, and you can override the # default by setting this flag. NTL_GF2X_ALTCODE=off # With this option, the default strategy for implmenting low-level GF2X # multiplication is replaced with an alternative strategy. This alternative # strategy seems to work better on RISC machines with deep pipelines and high # branch penalties (like a powerpc), but does no better (or even worse) on # x86s. NTL_GF2X_ALTCODE1=off # Yet another alternative implementation for GF2X multiplication. ########## More GMP Options: GMP_INCDIR=$(GMP_PREFIX)/include # directory containing gmp.h GMP_LIBDIR=$(GMP_PREFIX)/lib # directory containing libgmp.a ####### More gf2x options: GF2X_INCDIR=$(GF2X_PREFIX)/include # directory containing gf2x.h GF2X_LIBDIR=$(GF2X_PREFIX)/lib # directory containing libgf2x.a ntl-11.5.1/doc/version.txt0000644417616742025610000000135514064716023017155 0ustar gid-shoupvpug-gid-shoupv /**************************************************************************\ MODULE: version SUMMARY: Macros defining the NTL version number. \**************************************************************************/ #define NTL_VERSION ... // version number as a string, e.g., "5.2" #define NTL_MAJOR_VERSION ... // e.g., 5 in the above example #define NTL_MINOR_VERSION ... // e.g., 2 " #define NTL_REVISION ... // e.g., 0 " // The choice as to whether a new version warrants a higher // Major version number or Minor version number is fairly subjective, // with no particular rule. // Revision numbers are only used for small bug fixes that generally // do not affect the programming interface at all. ntl-11.5.1/doc/GF2.cpp.html0000644417616742025610000003072014064716023016752 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2.cpp.html


/**************************************************************************\

MODULE: GF2

SUMMARY:

The class GF2 represents the field GF(2).
Computationally speaking, it is not a particularly useful class.
Its main use is to make the interfaces to the various finite 
field classes as uniform as possible.

The header file for GF2 also declares the class ref_GF2, which
use used to represent non-const references to GF2's, such as
those obtained from indexing a vec_GF2, which "packs" GF2's
into words.

There are implicit conversions from ref_GF2 to const GF2
and from GF2& to ref_GF2.  Therefore, if you want to declare
a function that takes a non-const reference to a GF2, you
should declare the parameter of type ref_GF2: this will
allow you to pass variables of type GF2 as well as 
elements of vec_GF2's obtained through indexing.

For all functions defined below which take a parameter of type
GF2&, there is also a function that takes a parameter of type ref_GF2.
Theoretically, we could have just defined the functions that take
the ref_GF2 parameter type, because of the implicit conversion
from GF2& to ref_GF2; however, for efficiency reasons, both
flavors are actually provided.   It is recommended that higher-level
functions use the ref_GF2 type exclusively.


\**************************************************************************/

#include <NTL/ZZ.h>
#include <NTL/vector.h>


class GF2 {
public:

   GF2(); // initial value 0

   GF2(const GF2& a); // copy constructor
   explicit GF2(long a); // promotion constructor

   GF2& operator=(const GF2& a); // assignment
   GF2& operator=(long a); // assignment

   // typedefs to aid in generic programming
   typedef long rep_type;
   typedef GF2Context context_type;
   typedef GF2Bak bak_type;
   typedef GF2Push push_type;
   typedef GF2X poly_type;

};


long rep(GF2 a); // read-only access to representation of a





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(GF2 a, GF2 b);
long operator!=(GF2 a, GF2 b);

long IsZero(GF2 a);  // test for 0
long IsOne(GF2 a);  // test for 1

// PROMOTIONS: operators ==, != promote long to GF2 on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

GF2 operator+(GF2 a, GF2 b);
GF2 operator-(GF2 a, GF2 b);

GF2 operator-(GF2 a); // unary -

GF2& operator+=(GF2& x, GF2 a);
GF2& operator+=(GF2& x, long a);

GF2& operator-=(GF2& x, GF2 a);
GF2& operator-=(GF2& x, long a);

GF2& operator++(GF2& x);  // prefix
void operator++(GF2& x, int);  // postfix

GF2& operator--(GF2& x);  // prefix
void operator--(GF2& x, int);  // postfix

// procedural versions:


void add(GF2& x, GF2 a, GF2 b); // x = a + b
void sub(GF2& x, GF2 a, GF2 b); // x = a - b 
void negate(GF2& x, GF2 a); // x = -a

// PROMOTIONS: binary +, -, and procedures add, sub promote
// from long to GF2 on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

GF2 operator*(GF2 a, GF2 b);

GF2& operator*=(GF2& x, GF2 a);
GF2& operator*=(GF2& x, long a);

// procedural versions:

void mul(GF2& x, GF2 a, GF2 b); // x = a * b

void sqr(GF2& x, GF2 a); // x = a^2
GF2 sqr(GF2 a);

// PROMOTIONS: operator * and procedure mul promote from long to GF2
// on (a, b).


/**************************************************************************\

                                  Division

\**************************************************************************/

operator notation:

GF2 operator/(z_p a, GF2 b);

GF2& operator/=(GF2& x, GF2 a);
GF2& operator/=(GF2& x, long a);

procedural versions:

void div(GF2& x, GF2 a, GF2 b);
// x = a/b

void inv(GF2& x, GF2 a);
GF2 inv(GF2 a);
// x = 1/a

// PROMOTIONS: operator / and procedure div promote from long to GF2
// on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/


void power(GF2& x, GF2 a, long e); // x = a^e (e may be negative)
GF2 power(GF2 a, long e);


/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(GF2& x);
GF2 random_GF2();
// x = random element in GF2.  Uses RandomBnd from ZZ.


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, GF2 a);

istream& operator>>(istream& s, GF2& x);
// a ZZ is read and reduced mod 2


/**************************************************************************\

                               Miscellany

\**************************************************************************/


void clear(GF2& x); // x = 0
void set(GF2& x); // x = 1

void GF2::swap(GF2& x);
void swap(GF2& x, GF2& y);
// swap 

static GF2 GF2::zero();
// GF2::zero() yields a read-only reference to zero

static long GF2::modulus();
// GF2::modulus() returns the value 2

template<> class Vec<GF2>;
// Forward declaration of the explicit specialization
// of Vec<GF2>.  This specialization is defined in <NTL/vec_GF2.h>,
// which must be included in source files that need to use Vec<GF2>.

GF2::GF2(INIT_NO_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

GF2::GF2(INIT_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

GF2::allocate();
// provided for consistency with other classes, no action



ntl-11.5.1/doc/GF2E.cpp.html0000644417616742025610000005531114064716023017062 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2E.cpp.html


/**************************************************************************\

MODULE: GF2E

SUMMARY:

The class GF2E is used to represent polynomials in F_2[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  

Objects of the class GF2E are represented as a GF2X of degree < deg(P).

An executing program maintains a "current modulus", which is set to P using
GF2E::init(P).  The current modulus *must* be initialized before any operations
on GF2E's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes GF2EPush and GF2EContext below).


NOTE: if P is a trinomial X^n + X^k + 1, or a pentanomial
X^n + X^k3 + X^k2 + X^k1 + 1, or of the form X^n + g, where
g has low degree, then performance will be somewhat improved.
Such polynomials are constructed by the routines
BuildSparseIrred and BuildIrred in GF2XFactoring.


\**************************************************************************/

#include <NTL/GF2X.h>
#include <NTL/SmartPtr.h>


class GF2E {
public:

   GF2E(); // initial value 0

   GF2E(const GF2E& a); // copy constructor
   explicit GF2E(GF2 a); // promotion constructor
   explicit GF2E(long a); // promotion constructor

   GF2E& operator=(const GF2E& a); // assignment
   GF2E& operator=(GF2 a); // assignment
   GF2E& operator=(long a); // assignment

   ~GF2E(); // destructor

   GF2E(GF2E&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   GF2E& operator=(GF2E&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   static void init(const GF2X& P);
   // GF2E::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const GF2XModulus& modulus();
   // GF2E::modulus() yields read-only reference to the current modulus 

   static long degree();
   // GF2E::degree() returns deg(P)

   // typedefs to aid generic programming
   typedef GF2X rep_type;
   typedef GF2EContext context_type;
   typedef GF2EBak bak_type;
   typedef GF2EPush push_type;
   typedef GF2EX poly_type;

};


const GF2X& rep(const GF2E& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const GF2E& a, const GF2E& b);
long operator!=(const GF2E& a, const GF2E& b);

long IsZero(const GF2E& a);  // test for 0
long IsOne(const GF2E& a);  // test for 1

// PROMOTIONS: ==, != promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

GF2E operator+(const GF2E& a, const GF2E& b);

GF2E operator-(const GF2E& a, const GF2E& b);
GF2E operator-(const GF2E& a);

GF2E& operator+=(GF2E& x, const GF2E& a);
GF2E& operator+=(GF2E& x, GF2 a);
GF2E& operator+=(GF2E& x, long a);

GF2E& operator++(GF2E& x); // prefix
void operator++(GF2E& x, int); // postfix

GF2E& operator-=(GF2E& x, const GF2E& a);
GF2E& operator-=(GF2E& x, GF2 a);
GF2E& operator-=(GF2E& x, long a);

GF2E& operator--(GF2E& x); // prefix
void operator--(GF2E& x, int); // postfix

// procedural versions:

void add(GF2E& x, const GF2E& a, const GF2E& b); // x = a + b
void sub(GF2E& x, const GF2E& a, const GF2E& b); // x = a - b = a + b
void negate(GF2E& x, const GF2E& a); // x = - a = a

// PROMOTIONS: +, -, add, sub promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

GF2E operator*(const GF2E& a, const GF2E& b);

GF2E& operator*=(GF2E& x, const GF2E& a);
GF2E& operator*=(GF2E& x, GF2 a);
GF2E& operator*=(GF2E& x, long a);

// procedural versions:


void mul(GF2E& x, const GF2E& a, const GF2E& b); // x = a * b

void sqr(GF2E& x, const GF2E& a); // x = a^2
GF2E sqr(const GF2E& a);

// PROMOTIONS: *, mul promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

GF2E operator/(const GF2E& a, const GF2E& b);

GF2E& operator/=(GF2E& x, const GF2E& a);
GF2E& operator/=(GF2E& x, GF2 a);
GF2E& operator/=(GF2E& x, long a);


// procedural versions:

void div(GF2E& x, const GF2E& a, const GF2E& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(GF2E& x, const GF2E& a);
GF2E inv(const GF2E& a);
// x = 1/a

PROMOTIONS: /, div promote {long, GF2} to GF2E on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(GF2E& x, const GF2E& a, const ZZ& e);
GF2E power(const GF2E& a, const ZZ& e);

void power(GF2E& x, const GF2E& a, long e);
GF2E power(const GF2E& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(GF2E& x);
GF2E random_GF2E();
// x = random element in GF2E.

/**************************************************************************\

                                  Traces

\**************************************************************************/


void trace(GF2& x, const GF2E& a);  // x = trace of a
GF2 trace(const GF2E& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const GF2E& a);

istream& operator>>(istream& s, GF2E& x);
// a GF2X is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class GF2EPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      GF2EPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      GF2EPush push; // just backup current modulus

        ...

      GF2E::init(P1); // install P1 

        ...

      GF2E::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The GF2EPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see GF2EContext below.  There is also an older GF2EBak class
that may also be useful.

..........................................................................

It is critical that GF2E objects created under one GF2E modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
GF2E modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any GF2E object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


NOTE: the implementation of Vec<GF2E> is specialized to manage memory more
efficiently than in the default implementation of Vec<T>.  Specifically,
contiguous elements in a Vec<GF2E> are allocated in a contiguous region of
memory.  This reduces the number of calls to the memory allocator, and --- more
significantly --- leads to greater locality of reference.  A consequence of
this implementation is that any calls to SetLength on a Vec<GF2E> object will
need to use information about the current modulus, and so such calls should
only be done "in context".  That said, it is still safe to construct a
Vec<GF2E> using the default or copy contructor, and to assign or append one
Vec<GF2E> to another "out of context".

\**************************************************************************/


// A convenient interface for common cases

class GF2EPush {

public:
GF2EPush();  // backup current modulus
explicit GF2EPush(const GF2X& P);
explicit GF2EPush(const GF2EContext& context);
  // backup current modulus and install the given one

private:
GF2EPush(const GF2EPush&); // disabled
void operator=(const GF2EPush&); // disabled

};



// more general context switching:
// A GF2EContext object has a modulus Q (possibly "null"),

class GF2EContext {


public:

GF2EContext(); // Q = "null"
explicit GF2EContext(const GF2X& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

GF2EContext(const GF2EContext&);  // copy
GF2EContext& operator=(const GF2EContext&); // assignment
~GF2EContext(); // destructor


};


// An older interface:
// To describe this logic, think of a GF2EBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class GF2EBak {
public:


   GF2EBak();  // Q = "null", b = 0

   ~GF2EBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   GF2EBak(const GF2EBak&);  // copy disabled
   void operator=(const GF2EBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(GF2E& x); // x = 0
void set(GF2E& x); // x = 1

static const GF2E& GF2E::zero();
// GF2E::zero() yields a read-only reference to zero

static long GF2X::WordLength();
// GF2E::WordLength() returns # of words needed to store a polynomial of
// degree < GF2E::degree()

void GF2E::swap(GF2E& x);
void swap(GF2E& x, GF2E& y);
// swap (done by "pointer swapping", if possible).

static ZZ& GF2E::cardinality();
// yields the cardinality, i.e., 2^{GF2E::degree()}


GF2E::GF2E(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as GF2E x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

GF2E::GF2E(INIT_ALLOC_TYPE);
// special constructor: invoke as GF2E x(INIT_ALLOC);
// initializes x to 0, but allocates space 

GF2E::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus


ntl-11.5.1/doc/GF2EX.cpp.html0000644417616742025610000015625514064716023017223 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2EX.cpp.html

/**************************************************************************\

MODULE: GF2EX

SUMMARY:

The class GF2EX represents polynomials over GF2E,
and so can be used, for example, for arithmentic in GF(2^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
GF2E need not be a field.

\**************************************************************************/

#include <NTL/GF2E.h>
#include <NTL/vec_GF2E.h>

class GF2EX {
public:

   GF2EX(); // initial value 0

   GF2EX(const GF2EX& a); // copy
   explicit GF2EX(const GF2E& a);  // promotion
   explicit GF2EX(GF2 a);
   explicit GF2EX(long a);

   GF2EX& operator=(const GF2EX& a); // assignment
   GF2EX& operator=(const GF2E& a);
   GF2EX& operator=(GF2 a);
   GF2EX& operator=(long a);

   ~GF2EX(); // destructor


   GF2EX(GF2EX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   GF2EX& operator=(GF2EX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif


   GF2EX(INIT_MONO_TYPE, long i, const GF2E& c);
   GF2EX(INIT_MONO_TYPE, long i, GF2 c);
   GF2EX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as GF2EX(INIT_MONO, i, c)

   GF2EX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as GF2EX(INIT_MONO, i)




   // typedefs to aid in generic programming

   typedef GF2E coeff_type;
   typedef GF2EXModulus modulus_type;
   // ...

};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const GF2EX& a);  // return deg(a); deg(0) == -1.

const GF2E& coeff(const GF2EX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const GF2E& LeadCoeff(const GF2EX& a);
// returns leading term of a, or zero if a == 0

const GF2E& ConstTerm(const GF2EX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(GF2EX& x, long i, const GF2E& a);
void SetCoeff(GF2EX& x, long i, GF2 a);
void SetCoeff(GF2EX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(GF2EX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(GF2EX& x); // x is set to the monomial X

long IsX(const GF2EX& a); // test if x = X




GF2E& GF2EX::operator[](long i);
const GF2E& GF2EX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void GF2EX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void GF2EX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void GF2EX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.






/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const GF2EX& a, const GF2EX& b);
long operator!=(const GF2EX& a, const GF2EX& b);

long IsZero(const GF2EX& a); // test for 0
long IsOne(const GF2EX& a); // test for 1

// PROMOTIONS: ==, != promote {long,GF2,GF2E} to GF2EX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

GF2EX operator+(const GF2EX& a, const GF2EX& b);
GF2EX operator-(const GF2EX& a, const GF2EX& b);
GF2EX operator-(const GF2EX& a);

GF2EX& operator+=(GF2EX& x, const GF2EX& a);
GF2EX& operator+=(GF2EX& x, const GF2E& a);
GF2EX& operator+=(GF2EX& x, GF2 a);
GF2EX& operator+=(GF2EX& x, long a);


GF2EX& operator++(GF2EX& x);  // prefix
void operator++(GF2EX& x, int);  // postfix

GF2EX& operator-=(GF2EX& x, const GF2EX& a);
GF2EX& operator-=(GF2EX& x, const GF2E& a);
GF2EX& operator-=(GF2EX& x, GF2 a);
GF2EX& operator-=(GF2EX& x, long a);

GF2EX& operator--(GF2EX& x);  // prefix
void operator--(GF2EX& x, int);  // postfix

// procedural versions:

void add(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a + b
void sub(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a - b 
void negate(GF2EX& x, const GF2EX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,GF2,GF2E} to GF2EX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

GF2EX operator*(const GF2EX& a, const GF2EX& b);

GF2EX& operator*=(GF2EX& x, const GF2EX& a);
GF2EX& operator*=(GF2EX& x, const GF2E& a);
GF2EX& operator*=(GF2EX& x, GF2 a);
GF2EX& operator*=(GF2EX& x, long a);


// procedural versions:


void mul(GF2EX& x, const GF2EX& a, const GF2EX& b); // x = a * b

void sqr(GF2EX& x, const GF2EX& a); // x = a^2
GF2EX sqr(const GF2EX& a);

// PROMOTIONS: *, mul promote {long,GF2,GF2E} to GF2EX on (a, b).

void power(GF2EX& x, const GF2EX& a, long e);  // x = a^e (e >= 0)
GF2EX power(const GF2EX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

GF2EX operator<<(const GF2EX& a, long n);
GF2EX operator>>(const GF2EX& a, long n);

GF2EX& operator<<=(GF2EX& x, long n);
GF2EX& operator>>=(GF2EX& x, long n);

// procedural versions:

void LeftShift(GF2EX& x, const GF2EX& a, long n);
GF2EX LeftShift(const GF2EX& a, long n);

void RightShift(GF2EX& x, const GF2EX& a, long n);
GF2EX RightShift(const GF2EX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

GF2EX operator/(const GF2EX& a, const GF2EX& b);
GF2EX operator/(const GF2EX& a, const GF2E& b);
GF2EX operator/(const GF2EX& a, GF2 b);
GF2EX operator/(const GF2EX& a, long b);

GF2EX operator%(const GF2EX& a, const GF2EX& b);

GF2EX& operator/=(GF2EX& x, const GF2EX& a);
GF2EX& operator/=(GF2EX& x, const GF2E& a);
GF2EX& operator/=(GF2EX& x, GF2 a);
GF2EX& operator/=(GF2EX& x, long a);

GF2EX& operator%=(GF2EX& x, const GF2EX& a);

// procedural versions:


void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EX& b);
// q = a/b, r = a%b

void div(GF2EX& q, const GF2EX& a, const GF2EX& b);
void div(GF2EX& q, const GF2EX& a, const GF2E& b);
void div(GF2EX& q, const GF2EX& a, GF2 b);
void div(GF2EX& q, const GF2EX& a, long b);
// q = a/b

void rem(GF2EX& r, const GF2EX& a, const GF2EX& b);
// r = a%b

long divide(GF2EX& q, const GF2EX& a, const GF2EX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const GF2EX& a, const GF2EX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when GF2E is a field.

\**************************************************************************/


void GCD(GF2EX& x, const GF2EX& a, const GF2EX& b);
GF2EX GCD(const GF2EX& a, const GF2EX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(GF2EX& d, GF2EX& s, GF2EX& t, const GF2EX& a, const GF2EX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < GF2E::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo GF2E::modulus(), and leading
zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, GF2EX& x);
ostream& operator<<(ostream& s, const GF2EX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(GF2EX& x, const GF2EX& a); // x = derivative of a
GF2EX diff(const GF2EX& a);

void MakeMonic(GF2EX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(GF2EX& x, const GF2EX& a, long hi);
GF2EX reverse(const GF2EX& a, long hi);

void reverse(GF2EX& x, const GF2EX& a);
GF2EX reverse(const GF2EX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_GF2E& x, const GF2EX& a, long n);
vec_GF2E VectorCopy(const GF2EX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(GF2EX& x, long n);
GF2EX random_GF2EX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(GF2EX& x, const vec_GF2E& a);
GF2EX BuildFromRoots(const vec_GF2E& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(GF2E& b, const GF2EX& f, const GF2E& a);
GF2E eval(const GF2EX& f, const GF2E& a);
// b = f(a)

void eval(GF2E& b, const GF2X& f, const GF2E& a);
GF2E eval(const GF2EX& f, const GF2E& a);
// b = f(a); uses ModComp algorithm for GF2X

void eval(vec_GF2E& b, const GF2EX& f, const vec_GF2E& a);
vec_GF2E eval(const GF2EX& f, const vec_GF2E& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(GF2EX& f, const vec_GF2E& a, const vec_GF2E& b);
GF2EX interpolate(const vec_GF2E& a, const vec_GF2E& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(GF2EX& x, const GF2EX& a, long n); // x = a % X^n
GF2EX trunc(const GF2EX& a, long n);

void MulTrunc(GF2EX& x, const GF2EX& a, const GF2EX& b, long n);
GF2EX MulTrunc(const GF2EX& a, const GF2EX& b, long n);
// x = a * b % X^n

void SqrTrunc(GF2EX& x, const GF2EX& a, long n);
GF2EX SqrTrunc(const GF2EX& a, long n);
// x = a^2 % X^n

void InvTrunc(GF2EX& x, const GF2EX& a, long n);
GF2EX InvTrunc(GF2EX& x, const GF2EX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
GF2EXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EX& f);
GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EX& f);
// x = (a * b) % f

void SqrMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX SqrMod(const GF2EX& a, const GF2EX& f);
// x = a^2 % f

void MulByXMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX MulByXMod(const GF2EX& a, const GF2EX& f);
// x = (a * X) mod f

void InvMod(GF2EX& x, const GF2EX& a, const GF2EX& f);
GF2EX InvMod(const GF2EX& a, const GF2EX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(GF2EX& x, const GF2EX& a, const GF2EX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
GF2EXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/GF2EX.h>

void product(GF2EX& x, const vec_GF2EX& v, const GF2EX& f)
{
   GF2EXModulus F(f);
   GF2EX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A GF2EX may be used wherever a GF2EXModulus is required,
and a GF2EXModulus may be used wherever a GF2EX is required.


\**************************************************************************/

class GF2EXModulus {
public:
   GF2EXModulus(); // initially in an unusable state

   GF2EXModulus(const GF2EX& f); // initialize with f, deg(f) > 0

   GF2EXModulus(const GF2EXModulus&); // copy

   GF2EXModulus& operator=(const GF2EXModulus&); // assignment

   ~GF2EXModulus(); // destructor

   operator const GF2EX& () const; // implicit read-only access to f

   const GF2EX& val() const; // explicit read-only access to f
};

void build(GF2EXModulus& F, const GF2EX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration GF2EXModulus F(f) is
// equivalent to GF2EXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const GF2EXModulus& F);  // return n=deg(f)

void MulMod(GF2EX& x, const GF2EX& a, const GF2EX& b, const GF2EXModulus& F);
GF2EX MulMod(const GF2EX& a, const GF2EX& b, const GF2EXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(GF2EX& x, const GF2EX& a, const GF2EXModulus& F);
GF2EX SqrMod(const GF2EX& a, const GF2EXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(GF2EX& x, const GF2EX& a, const ZZ& e, const GF2EXModulus& F);
GF2EX PowerMod(const GF2EX& a, const ZZ& e, const GF2EXModulus& F);

void PowerMod(GF2EX& x, const GF2EX& a, long e, const GF2EXModulus& F);
GF2EX PowerMod(const GF2EX& a, long e, const GF2EXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(GF2EX& x, const ZZ& e, const GF2EXModulus& F);
GF2EX PowerXMod(const ZZ& e, const GF2EXModulus& F);

void PowerXMod(GF2EX& x, long e, const GF2EXModulus& F);
GF2EX PowerXMod(long e, const GF2EXModulus& F);

// x = X^e % f (e may be negative)

void rem(GF2EX& x, const GF2EX& a, const GF2EXModulus& F);
// x = a % f

void DivRem(GF2EX& q, GF2EX& r, const GF2EX& a, const GF2EXModulus& F);
// q = a/f, r = a%f

void div(GF2EX& q, const GF2EX& a, const GF2EXModulus& F);
// q = a/f

// operator notation:

GF2EX operator/(const GF2EX& a, const GF2EXModulus& F);
GF2EX operator%(const GF2EX& a, const GF2EXModulus& F);

GF2EX& operator/=(GF2EX& x, const GF2EXModulus& F);
GF2EX& operator%=(GF2EX& x, const GF2EXModulus& F);



/**************************************************************************\

                             vectors of GF2EX's

\**************************************************************************/

typedef Vec<GF2EX> vec_GF2EX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(GF2EX& x, const GF2EX& g, const GF2EX& h, const GF2EXModulus& F);
GF2EX CompMod(const GF2EX& g, const GF2EX& h,
                    const GF2EXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(GF2EX& x1, GF2EX& x2, const GF2EX& g1, const GF2EX& g2,
              const GF2EX& h, const GF2EXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(GF2EX& x1, GF2EX& x2, GF2EX& x3,
              const GF2EX& g1, const GF2EX& g2, const GF2EX& g3,
              const GF2EX& h, const GF2EXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a GF2EXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct GF2EXArgument {
   vec_GF2EX H;
};

void build(GF2EXArgument& H, const GF2EX& h, const GF2EXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(GF2EX& x, const GF2EX& g, const GF2EXArgument& H,
             const GF2EXModulus& F);

GF2EX CompMod(const GF2EX& g, const GF2EXArgument& H,
                    const GF2EXModulus& F);

extern thread_local long GF2EXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// GF2EXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in GF2EXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(GF2E& x, const GF2EVector& a, const GF2EX& b);
GF2E project(const GF2EVector& a, const GF2EX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k,
                   const GF2EX& h, const GF2EXModulus& F);

vec_GF2E ProjectPowers(const vec_GF2E& a, long k,
                   const GF2EX& h, const GF2EXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_GF2E& x, const vec_GF2E& a, long k,
                   const GF2EXArgument& H, const GF2EXModulus& F);

vec_GF2E ProjectPowers(const vec_GF2E& a, long k,
                   const GF2EXArgument& H, const GF2EXModulus& F);

// same as above, but uses a pre-computed GF2EXArgument

class GF2EXTransMultiplier { /* ... */ };

void build(GF2EXTransMultiplier& B, const GF2EX& b, const GF2EXModulus& F);



void UpdateMap(vec_GF2E& x, const vec_GF2E& a,
               const GF2EXMultiplier& B, const GF2EXModulus& F);

vec_GF2E UpdateMap(const vec_GF2E& a,
               const GF2EXMultiplier& B, const GF2EXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when GF2E is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(GF2EX& h, const vec_GF2E& a, long m);
GF2EX MinPolySeq(const vec_GF2E& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void ProbMinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX ProbMinPolyMod(const GF2EX& g, const GF2EXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{GF2E::degree()}.

void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void MinPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX MinPolyMod(const GF2EX& g, const GF2EXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F, long m);
GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F, long m);

void IrredPolyMod(GF2EX& h, const GF2EX& g, const GF2EXModulus& F);
GF2EX IrredPolyMod(const GF2EX& g, const GF2EXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

GF2E need not be a field.

\**************************************************************************/


void CompTower(GF2EX& x, const GF2X& g, const GF2EXArgument& h,
             const GF2EXModulus& F);

GF2EX CompTower(const GF2X& g, const GF2EXArgument& h,
             const GF2EXModulus& F);

void CompTower(GF2EX& x, const GF2X& g, const GF2EX& h,
             const GF2EXModulus& F);

GF2EX CompTower(const GF2X& g, const GF2EX& h,
             const GF2EXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F,
                      long m);

GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void ProbMinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X ProbMinPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over GF2.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*GF2E::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m);

GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void MinPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X MinPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F, long m);

GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F, long m);

void IrredPolyTower(GF2X& h, const GF2EX& g, const GF2EXModulus& F);

GF2X IrredPolyTower(const GF2EX& g, const GF2EXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.



/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(GF2E& x, const GF2EX& a, const GF2EXModulus& F);
GF2E TraceMod(const GF2EX& a, const GF2EXModulus& F);

void TraceMod(GF2E& x, const GF2EX& a, const GF2EX& f);
GF2E TraceMod(const GF2EX& a, const GF2EXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_GF2E& S, const GF2EX& f);
vec_GF2E TraceVec(const GF2EX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(GF2E& x, const GF2EX& a, const GF2EX& f);
GF2E NormMod(const GF2EX& a, const GF2EX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(GF2E& x, const GF2EX& a, const GF2EX& b);
GF2E resultant(const GF2EX& a, const GF2EX& b);
// x = resultant(a, b)

// NormMod and resultant require that GF2E is a field.



/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(GF2EX& x) // x = 0
void set(GF2EX& x); // x = 1


void GF2EX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

GF2EX::GF2EX(INIT_SIZE_TYPE, long n);
// GF2EX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const GF2EX& zero();
// GF2EX::zero() is a read-only reference to 0

void GF2EX::swap(GF2EX& x);
void swap(GF2EX& x, GF2EX& y);
// swap (via "pointer swapping")

GF2EX::GF2EX(long i, const GF2E& c);
GF2EX::GF2EX(long i, GF2 c);
GF2EX::GF2EX(long i, long c);
// initialize to X^i*c, provided for backward compatibility

ntl-11.5.1/doc/GF2EXFactoring.cpp.html0000644417616742025610000003654614064716023021060 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2EXFactoring.cpp.html

/**************************************************************************\

MODULE: GF2EXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over GF2E, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/GF2EX.h>
#include <NTL/pair_GF2EX_long.h>

void SquareFreeDecomp(vec_pair_GF2EX_long& u, const GF2EX& f);
vec_pair_GF2EX_long SquareFreeDecomp(const GF2EX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_GF2E& x, const GF2EX& f);
vec_GF2E FindRoots(const GF2EX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(GF2E& root, const GF2EX& f);
GF2E FindRoot(const GF2EX& f);


// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX  SFBerlekamp(const GF2EX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].


void berlekamp(vec_pair_GF2EX_long& factors, const GF2EX& f,
               long verbose=0);

vec_pair_GF2EX_long berlekamp(const GF2EX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_GF2EX_long& factors, const GF2EX& f, const GF2EX& h,
         long verbose=0);

vec_pair_GF2EX_long NewDDF(const GF2EX& f, const GF2EX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{2^{GF2E::degree()}} mod f,
// which can be computed efficiently using the function FrobeniusMap 
// (see below).
// This routine  implements the baby step/giant step algorithm 
// of [Kaltofen and Shoup, STOC 1995], 
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form tmp-*.
// The definition of "large" is controlled by the variable

      extern thread_local double GF2EXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds GF2EXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).



void EDF(vec_GF2EX& factors, const GF2EX& f, const GF2EX& h,
         long d, long verbose=0);

vec_GF2EX EDF(const GF2EX& f, const GF2EX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  
// h = X^{2^{GF2E::degree()}} mod f,
// which can be computed efficiently using the function FrobeniusMap 
// (see below).
// d = degree of irreducible factors of f.  
// This routine implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX RootEDF(const GF2EX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_GF2EX& factors, const GF2EX& f, long verbose=0);
vec_GF2EX SFCanZass(const GF2EX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_GF2EX_long& factors, const GF2EX& f,
             long verbose=0);

vec_pair_GF2EX_long CanZass(const GF2EX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// GF2EXArgBound (see GF2EX.txt).

// NOTE: In most situations, you should use the CanZass factoring
// routine, rather than Berlekamp: it is faster and uses less space.



void mul(GF2EX& f, const vec_pair_GF2EX_long& v);
GF2EX mul(const vec_pair_GF2EX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const GF2EX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// 2^{-iter*GF2E::degree()}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const GF2EX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const GF2EX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(GF2EX& f, long n);
GF2EX BuildIrred_GF2EX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(GF2EX& f, const GF2EX& g);
GF2EX BuildRandomIrred(const GF2EX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

void FrobeniusMap(GF2EX& h, const GF2EXModulus& F);
GF2EX FrobeniusMap(const GF2EXModulus& F);

// Computes h = X^{2^{GF2E::degree()}} mod F, 
// by either iterated squaring or modular
// composition.  The latter method is based on a technique developed
// in Kaltofen & Shoup (Faster polynomial factorization over high
// algebraic extensions of finite fields, ISSAC 1997).  This method is
// faster than iterated squaring when deg(F) is large relative to
// GF2E::degree().


long IterComputeDegree(const GF2EX& h, const GF2EXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{2^{GF2E::degree()}} mod f (see function FrobeniusMap above) 
// The common degree of the irreducible factors
// of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const GF2EX& h, const GF2EXModulus& F);

// f is assumed to be an "equal degree" polynomial, h = X^{2^{GF2E::degree()}}
// mod f (see function FrobeniusMap above).  
// The common degree of the irreducible factors of f is
// computed. Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(GF2EX& w, const GF2EX& a, long d, const GF2EXModulus& F,
              const GF2EX& h);

GF2EX TraceMap(const GF2EX& a, long d, const GF2EXModulus& F,
              const GF2EX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of 2^{GF2E::degree()}.  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992].
// If q = 2^{GF2E::degree()}, then h can be computed most efficiently
// by using the function FrobeniusMap above.

void PowerCompose(GF2EX& w, const GF2EX& h, long d, const GF2EXModulus& F);

GF2EX PowerCompose(const GF2EX& h, long d, const GF2EXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of 2^{GF2E::degree()}.  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992].
// If q = 2^{GF2E::degree()}, then h can be computed most efficiently
// by using the function FrobeniusMap above.

ntl-11.5.1/doc/GF2X.cpp.html0000644417616742025610000014367214064716023017115 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2X.cpp.html

/**************************************************************************\

MODULE: GF2X

SUMMARY:

The class GF2X implements polynomial arithmetic modulo 2.

Polynomial arithmetic is implemented using a combination of classical
routines and Karatsuba.

\**************************************************************************/

#include <NTL/GF2.h>
#include <NTL/vec_GF2.h>

class GF2X {
public:

   GF2X(); // initial value 0

   GF2X(const GF2X& a); // copy
   explicit GF2X(long a); // promotion
   explicit GF2X(GF2 a); // promotion

   GF2X& operator=(const GF2X& a); // assignment
   GF2X& operator=(GF2 a);
   GF2X& operator=(long a);

   ~GF2X(); // destructor

   GF2X(GF2X&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   GF2X& operator=(GF2X&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   GF2X(INIT_MONO_TYPE, long i, GF2 c);
   GF2X(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as GF2X(INIT_MONO, i, c)

   GF2X(INIT_MONO_TYPE, long i);
   // initialize to c*X^i, invoke as GF2X(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef GF2 coeff_type;
   typedef GF2E residue_type;
   typedef GF2XModulus modulus_type;


   // ...

};



/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: unlike other polynomial classes, the coefficient vector
for GF2X has a special representation, packing coefficients into 
words.  This has two consequences.  First, when using the indexing
notation on a non-const polynomial f, the return type is ref_GF2,
rather than GF2&.  For the most part, a ref_GF2 may be used like
a GF2& --- see GF2.txt for more details.  Second, when applying 
f.SetLength(n) to a polynomial f, this essentially has the effect
of zeroing out the coefficients of X^i for i >= n.

\**************************************************************************/

long deg(const GF2X& a);  // return deg(a); deg(0) == -1.

const GF2 coeff(const GF2X& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const GF2 LeadCoeff(const GF2X& a);
// returns leading term of a, or zero if a == 0

const GF2 ConstTerm(const GF2X& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(GF2X& x, long i, GF2 a);
void SetCoeff(GF2X& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(GF2X& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(GF2X& x); // x is set to the monomial X

long IsX(const GF2X& a); // test if x = X




ref_GF2 GF2X::operator[](long i);
const GF2 GF2X::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f)

void GF2X::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void GF2X::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void GF2X::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const GF2X& a, const GF2X& b);
long operator!=(const GF2X& a, const GF2X& b);

long IsZero(const GF2X& a); // test for 0
long IsOne(const GF2X& a); // test for 1

// PROMOTIONS: operators ==, != promote {long, GF2} to GF2X on (a, b)


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

GF2X operator+(const GF2X& a, const GF2X& b);
GF2X operator-(const GF2X& a, const GF2X& b);

GF2X operator-(const GF2X& a); // unary -

GF2X& operator+=(GF2X& x, const GF2X& a);
GF2X& operator+=(GF2X& x, GF2 a);
GF2X& operator+=(GF2X& x, long a);

GF2X& operator-=(GF2X& x, const GF2X& a);
GF2X& operator-=(GF2X& x, GF2 a);
GF2X& operator-=(GF2X& x, long a);

GF2X& operator++(GF2X& x);  // prefix
void operator++(GF2X& x, int);  // postfix

GF2X& operator--(GF2X& x);  // prefix
void operator--(GF2X& x, int);  // postfix

// procedural versions:


void add(GF2X& x, const GF2X& a, const GF2X& b); // x = a + b
void sub(GF2X& x, const GF2X& a, const GF2X& b); // x = a - b
void negate(GF2X& x, const GF2X& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, GF2}
// to GF2X on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

GF2X operator*(const GF2X& a, const GF2X& b);

GF2X& operator*=(GF2X& x, const GF2X& a);
GF2X& operator*=(GF2X& x, GF2 a);
GF2X& operator*=(GF2X& x, long a);

// procedural versions:

void mul(GF2X& x, const GF2X& a, const GF2X& b); // x = a * b

void sqr(GF2X& x, const GF2X& a); // x = a^2
GF2X sqr(const GF2X& a);

// PROMOTIONS: operator * and procedure mul promote {long, GF2} to GF2X
// on (a, b).


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

GF2X operator<<(const GF2X& a, long n);
GF2X operator>>(const GF2X& a, long n);

GF2X& operator<<=(GF2X& x, long n);
GF2X& operator>>=(GF2X& x, long n);

// procedural versions:

void LeftShift(GF2X& x, const GF2X& a, long n);
GF2X LeftShift(const GF2X& a, long n);

void RightShift(GF2X& x, const GF2X& a, long n);
GF2X RightShift(const GF2X& a, long n);

void MulByX(GF2X& x, const GF2X& a);
GF2X MulByX(const GF2X& a);


/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

GF2X operator/(const GF2X& a, const GF2X& b);
GF2X operator%(const GF2X& a, const GF2X& b);

GF2X& operator/=(GF2X& x, const GF2X& a);
GF2X& operator/=(GF2X& x, GF2 a);
GF2X& operator/=(GF2X& x, long a);

GF2X& operator%=(GF2X& x, const GF2X& b);


// procedural versions:


void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2X& b);
// q = a/b, r = a%b

void div(GF2X& q, const GF2X& a, const GF2X& b);
// q = a/b

void rem(GF2X& r, const GF2X& a, const GF2X& b);
// r = a%b

long divide(GF2X& q, const GF2X& a, const GF2X& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const GF2X& a, const GF2X& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

// PROMOTIONS: operator / and procedure div promote {long, GF2} to GF2X
// on (a, b).


/**************************************************************************\

                                   GCD's

\**************************************************************************/


void GCD(GF2X& x, const GF2X& a, const GF2X& b);
GF2X GCD(const GF2X& a, const GF2X& b);
// x = GCD(a, b) (zero if a==b==0).


void XGCD(GF2X& d, GF2X& s, GF2X& t, const GF2X& a, const GF2X& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be 0 or 1, and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
may be arbitrary integers which are reduced modulo 2, and leading zeros
stripped.

There is also a more compact hex I/O format.  To output in this
format, set GF2X::HexOutput to a nonzero value.  On input, if the first
non-blank character read is 'x' or 'X', then a hex format is assumed.


\**************************************************************************/

istream& operator>>(istream& s, GF2X& x);
ostream& operator<<(ostream& s, const GF2X& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(GF2X& x, const GF2X& a);
GF2X diff(const GF2X& a);
// x = derivative of a


void reverse(GF2X& x, const GF2X& a, long hi);
GF2X reverse(const GF2X& a, long hi);

void reverse(GF2X& x, const GF2X& a);
GF2X reverse(const GF2X& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version


void VectorCopy(vec_GF2& x, const GF2X& a, long n);
vec_GF2 VectorCopy(const GF2X& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.

// Note that there is also a conversion routine from GF2X to vec_GF2
// that makes the length of the vector match the number of coefficients
// of the polynomial.

long weight(const GF2X& a);
// returns the # of nonzero coefficients in a

void GF2XFromBytes(GF2X& x, const unsigned char *p, long n);
GF2X GF2XFromBytes(const unsigned char *p, long n);
// conversion from byte vector to polynomial.
// x = sum(p[i]*X^(8*i), i = 0..n-1), where the bits of p[i] are interpretted
// as a polynomial in the natural way (i.e., p[i] = 1 is interpretted as 1,
// p[i] = 2 is interpretted as X, p[i] = 3 is interpretted as X+1, etc.).
// In the unusual event that characters are wider than 8 bits,
// only the low-order 8 bits of p[i] are used.

void BytesFromGF2X(unsigned char *p, const GF2X& a, long n);
// conversion from polynomial to byte vector.
// p[0..n-1] are computed so that 
//     a = sum(p[i]*X^(8*i), i = 0..n-1) mod X^(8*n),
// where the values p[i] are interpretted as polynomials as in GF2XFromBytes
// above.

long NumBits(const GF2X& a);
// returns number of bits of a, i.e., deg(a) + 1.

long NumBytes(const GF2X& a);
// returns number of bytes of a, i.e., floor((NumBits(a)+7)/8)




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(GF2X& x, long n);
GF2X random_GF2X(long n);
// x = random polynomial of degree < n 



/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(GF2X& x, const GF2X& a, long n); // x = a % X^n
GF2X trunc(const GF2X& a, long n);

void MulTrunc(GF2X& x, const GF2X& a, const GF2X& b, long n);
GF2X MulTrunc(const GF2X& a, const GF2X& b, long n);
// x = a * b % X^n

void SqrTrunc(GF2X& x, const GF2X& a, long n);
GF2X SqrTrunc(const GF2X& a, long n);
// x = a^2 % X^n

void InvTrunc(GF2X& x, const GF2X& a, long n);
GF2X InvTrunc(const GF2X& a, long n);
// computes x = a^{-1} % X^n.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
GF2XModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2X& f);
GF2X MulMod(const GF2X& a, const GF2X& b, const GF2X& f);
// x = (a * b) % f

void SqrMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X SqrMod(const GF2X& a, const GF2X& f);
// x = a^2 % f

void MulByXMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X MulByXMod(const GF2X& a, const GF2X& f);
// x = (a * X) mod f

void InvMod(GF2X& x, const GF2X& a, const GF2X& f);
GF2X InvMod(const GF2X& a, const GF2X& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(GF2X& x, const GF2X& a, const GF2X& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
GF2XModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include <NTL/GF2X.h>

void product(GF2X& x, const vec_GF2X& v, const GF2X& f)
{
   GF2XModulus F(f);
   GF2X res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}


Note that automatic conversions are provided so that a GF2X can
be used wherever a GF2XModulus is required, and a GF2XModulus
can be used wherever a GF2X is required.

The GF2XModulus routines optimize several important special cases:

  - f = X^n + X^k + 1, where k <= min((n+1)/2, n-NTL_BITS_PER_LONG)

  - f = X^n + X^{k_3} + X^{k_2} + X^{k_1} + 1,
      where k_3 <= min((n+1)/2, n-NTL_BITS_PER_LONG)

  - f = X^n + g, where deg(g) is small


\**************************************************************************/

class GF2XModulus {
public:
   GF2XModulus(); // initially in an unusable state
   ~GF2XModulus();

   GF2XModulus(const GF2XModulus&);  // copy

   GF2XModulus& operator=(const GF2XModulus&);   // assignment

   GF2XModulus(const GF2X& f); // initialize with f, deg(f) > 0

   operator const GF2X& () const;
   // read-only access to f, implicit conversion operator

   const GF2X& val() const;
   // read-only access to f, explicit notation

   long WordLength() const;
   // returns word-length of resisues
};

void build(GF2XModulus& F, const GF2X& f);
// pre-computes information about f and stores it in F; deg(f) > 0.
// Note that the declaration GF2XModulus F(f) is equivalent to
// GF2XModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const GF2XModulus& F);  // return deg(f)

void MulMod(GF2X& x, const GF2X& a, const GF2X& b, const GF2XModulus& F);
GF2X MulMod(const GF2X& a, const GF2X& b, const GF2XModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(GF2X& x, const GF2X& a, const GF2XModulus& F);
GF2X SqrMod(const GF2X& a, const GF2XModulus& F);
// x = a^2 % f; deg(a) < n

void MulByXMod(GF2X& x, const GF2X& a, const GF2XModulus& F);
GF2X MulByXMod(const GF2X& a, const GF2XModulus& F);
// x = (a * X) mod F

void PowerMod(GF2X& x, const GF2X& a, const ZZ& e, const GF2XModulus& F);
GF2X PowerMod(const GF2X& a, const ZZ& e, const GF2XModulus& F);

void PowerMod(GF2X& x, const GF2X& a, long e, const GF2XModulus& F);
GF2X PowerMod(const GF2X& a, long e, const GF2XModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(GF2X& x, const ZZ& e, const GF2XModulus& F);
GF2X PowerXMod(const ZZ& e, const GF2XModulus& F);

void PowerXMod(GF2X& x, long e, const GF2XModulus& F);
GF2X PowerXMod(long e, const GF2XModulus& F);

// x = X^e % f (e may be negative)


void rem(GF2X& x, const GF2X& a, const GF2XModulus& F);
// x = a % f

void DivRem(GF2X& q, GF2X& r, const GF2X& a, const GF2XModulus& F);
// q = a/f, r = a%f

void div(GF2X& q, const GF2X& a, const GF2XModulus& F);
// q = a/f

// operator notation:

GF2X operator/(const GF2X& a, const GF2XModulus& F);
GF2X operator%(const GF2X& a, const GF2XModulus& F);

GF2X& operator/=(GF2X& x, const GF2XModulus& F);
GF2X& operator%=(GF2X& x, const GF2XModulus& F);


/**************************************************************************\

                             vectors of GF2X's

\**************************************************************************/


typedef Vec<GF2X> vec_GF2X; // backward compatibility


/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.



\**************************************************************************/

void CompMod(GF2X& x, const GF2X& g, const GF2X& h, const GF2XModulus& F);
GF2X CompMod(const GF2X& g, const GF2X& h, const GF2XModulus& F);
// x = g(h) mod f; deg(h) < n

void Comp2Mod(GF2X& x1, GF2X& x2, const GF2X& g1, const GF2X& g2,
              const GF2X& h, const GF2XModulus& F);
// xi = gi(h) mod f (i=1,2), deg(h) < n.

void CompMod3(GF2X& x1, GF2X& x2, GF2X& x3,
              const GF2X& g1, const GF2X& g2, const GF2X& g3,
              const GF2X& h, const GF2XModulus& F);
// xi = gi(h) mod f (i=1..3), deg(h) < n


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a GF2XArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct GF2XArgument {
   vec_GF2X H;
};

void build(GF2XArgument& H, const GF2X& h, const GF2XModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n

void CompMod(GF2X& x, const GF2X& g, const GF2XArgument& H,
             const GF2XModulus& F);

GF2X CompMod(const GF2X& g, const GF2XArgument& H,
             const GF2XModulus& F);


extern thread_local long GF2XArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// GF2XArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in GF2XFactoring.

/**************************************************************************\

                     Power Projection routines

\**************************************************************************/

void project(GF2& x, const vec_GF2& a, const GF2X& b);
GF2 project(const vec_GF2& a, const GF2X& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k,
                   const GF2X& h, const GF2XModulus& F);

vec_GF2 ProjectPowers(const vec_GF2& a, long k,
                   const GF2X& h, const GF2XModulus& F);

// Computes the vector 

//   (project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// Restriction: must have a.length <= deg(F) and deg(h) < deg(F).
// This operation is really the "transpose" of the modular composition 
// operation.

void ProjectPowers(vec_GF2& x, const vec_GF2& a, long k,
                   const GF2XArgument& H, const GF2XModulus& F);

vec_GF2 ProjectPowers(const vec_GF2& a, long k,
                   const GF2XArgument& H, const GF2XModulus& F);

// same as above, but uses a pre-computed GF2XArgument


// lower-level routines for transposed modular multiplication:

class GF2XTransMultiplier { /* ... */ };

void build(GF2XTransMultiplier& B, const GF2X& b, const GF2XModulus& F);

// build a GF2XTransMultiplier to use in the following routine:

void UpdateMap(vec_GF2& x, const vec_GF2& a, const GF2XTransMultiplier& B,
         const GF2XModulus& F);

vec_GF2 UpdateMap(const vec_GF2& a, const GF2XTransMultiplier& B,
         const GF2XModulus& F);

// Computes the vector

//   project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: must have a.length() <= deg(F) and deg(b) < deg(F).
// This is really the transpose of modular multiplication.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(GF2X& h, const vec_GF2& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void ProbMinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X ProbMinPolyMod(const GF2X& g, const GF2XModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic; it always
// returns a divisor of the minimal polynomial, possibly a proper divisor.

void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void MinPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X MinPolyMod(const GF2X& g, const GF2XModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F, long m);
GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F, long m);

void IrredPolyMod(GF2X& h, const GF2X& g, const GF2XModulus& F);
GF2X IrredPolyMod(const GF2X& g, const GF2XModulus& F);

// same as above, but assumes that F is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                                Traces

\**************************************************************************/


void TraceMod(GF2& x, const GF2X& a, const GF2XModulus& F);
GF2 TraceMod(const GF2X& a, const GF2XModulus& F);

void TraceMod(GF2& x, const GF2X& a, const GF2X& f);
GF2 TraceMod(const GF2X& a, const GF2X& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_GF2& S, const GF2X& f);
vec_GF2 TraceVec(const GF2X& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].


/**************************************************************************\

                           Miscellany

\**************************************************************************/


void clear(GF2X& x) // x = 0
void set(GF2X& x); // x = 1


void GF2X::kill();
// f.kill() sets f to 0 and frees all memory held by f.  

GF2X::GF2X(INIT_SIZE_TYPE, long n);
// GF2X(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const GF2X& zero();
// GF2X::zero() is a read-only reference to 0

void GF2X::swap(GF2X& x);
void swap(GF2X& x, GF2X& y);
// swap (via "pointer swapping" -- if possible)

GF2X::GF2X(long i, GF2 c);
GF2X::GF2X(long i, long c);
// initialize to c*X^i, provided for backward compatibility

// SIZE INVARIANT: for any f in GF2X, deg(f)+1 < 2^(NTL_BITS_PER_LONG-4).
ntl-11.5.1/doc/GF2XFactoring.cpp.html0000644417616742025610000002014614064716023020740 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2XFactoring.cpp.html

/**************************************************************************\

MODULE: GF2XFactoring

SUMMARY:

Routines are provided for factorization in F_2[X], as well as routines
for related problems such as testing irreducibility and constructing
irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/GF2X.h>
#include <NTL/pair_GF2X_long.h>

void SquareFreeDecomp(vec_pair_GF2X_long& u, const GF2X& f);
vec_pair_GF2X_long SquareFreeDecomp(const GF2X& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void DDF(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0);
vec_pair_GF2X_long DDF(const GF2X& f, long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.



void EDF(vec_GF2X& factors, const GF2X& f, long d, long verbose=0);
vec_GF2X EDF(const GF2X& f, long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  d = degree of
// irreducible factors of f

void SFCanZass(vec_GF2X& factors, const GF2X& f, long verbose=0);
vec_GF2X SFCanZass(const GF2X& f, long verbose=0);


// Assumes f is monic and square-free.  returns list of factors of f.


void CanZass(vec_pair_GF2X_long& factors, const GF2X& f, long verbose=0);
vec_pair_GF2X_long CanZass(const GF2X& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.


void mul(GF2X& f, const vec_pair_GF2X_long& v);
GF2X mul(const vec_pair_GF2X_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long IterIrredTest(const GF2X& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildSparseIrred(GF2X& f, long n);
GF2X BuildSparseIrred_GF2X(long n);

// Builds a monic irreducible polynomial of degree n.
// If there is an irreducible trinomial X^n + X^k + 1,
// then the one with minimal k is chosen.
// Otherwise, if there is an irreducible pentanomial 
// X^n + X^k3 + X^k2 + x^k1 + 1, then the one with minimal
// k3 is chosen (minimizing first k2 and then k1).
// Otherwise, if there is niether an irreducible trinomial
// or pentanomial, the routine result from BuildIrred (see below)
// is chosen---this is probably only of academic interest,
// since it a reasonable, but unproved, conjecture that they
// exist for every n > 1.

// For n <= 2048, the polynomial is constructed
// by table lookup in a pre-computed table.

// The GF2XModulus data structure and routines (and indirectly GF2E) 
// are optimized to deal with the output from BuildSparseIrred.

void BuildIrred(GF2X& f, long n);
GF2X BuildIrred_GF2X(long n);

// Build a monic irreducible poly of degree n.  The polynomial
// constructed is "canonical" in the sense that it is of the form
// f=X^n + g, where the bits of g are the those of the smallest
// non-negative integer that make f irreducible.  

// The GF2XModulus data structure and routines (and indirectly GF2E) 
// are optimized to deal with the output from BuildIrred.

// Note that the output from BuildSparseIrred will generally yield
// a "better" representation (in terms of efficiency) for
// GF(2^n) than the output from BuildIrred.



void BuildRandomIrred(GF2X& f, const GF2X& g);
GF2X BuildRandomIrred(const GF2X& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

ntl-11.5.1/doc/GF2XVec.cpp.html0000644417616742025610000001102314064716023017533 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/GF2XVec.cpp.html

/**************************************************************************\

MODULE: GF2XVec

SUMMARY:

The class GF2XVec implements vectors of fixed-length GF2X's.  You can
allocate a vector of GF2X's of a specified length, where the maximum
size of each GF2X is also specified.  These parameters can be specified
either with a constructor, or with SetSize.  It is an error to
try to re-size a vector of non-xero , or store a GF2X that doesn't fit.  
The space can be released with "kill", and then you are free to call SetSize
again.  If you want more flexible---but less efficient---vectors, use
vec_GF2X.

\**************************************************************************/

#include <NTL/GF2X.h>


class GF2XVec {
public:
   GF2XVec();

   GF2XVec& operator=(const GF2XVec&);
   // first kill()'s destination (unless source and destination are
   // identical)

   GF2XVec(const GF2XVec&);

   ~GF2XVec();

   GF2XVec(GF2XVec&& other) noexcept;
   GF2XVec& operator=(GF2XVec&& other) noexcept;


   GF2XVec(long n, long d);
   // sets length to n and max size of each element to d,
   // where the size d measures the number of words 

   void SetSize(long n, long d);
   // sets length to n and max size of each element to d,
   // where the size d measures the number of words 

   long length() const;
   // length of vector

   long BaseSize() const;
   // max size of each element

   void kill();
   // release space


   GF2X* elts();
   const GF2X* elts() const;
   // pointer to first element

   GF2X& operator[](long i);
   const GF2X& operator[](long i) const;
   // indexing operator; starts at 0; no range checking

   swap(GF2XVec& x);
   // swap with x by swapping pointers

   void move(GF2XVec& other);
   // quick move other to *this
};


void swap(GF2XVec& x, GF2XVec& y);
// swaps x and y by swapping pointers

ntl-11.5.1/doc/HNF.cpp.html0000644417616742025610000000502014064716023017002 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/HNF.cpp.html

/**************************************************************************\

MODULE: HNF

SUMMARY:

A routine for computing Hermite Normal Forms

\**************************************************************************/


#include <NTL/mat_ZZ.h>

void HNF(mat_ZZ& W, const mat_ZZ& A, const ZZ& D);

// The input matrix A is an n x m matrix of rank m (so n >= m), and D
// is a multiple of the determinant of the lattice L spanned by the
// rows of A.  W is computed as the Hermite Normal Form of A; that is,
// W is the unique m x m matrix whose rows span L, such that

//   - W is lower triangular,
//   - the diagonal entries are positive,
//   - any entry below the diagonal is a non-negative number
//     strictly less than the diagonal entry in its column.

// Currently, this is implemented using the algorithm of [P. Domich,
// R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987].

ntl-11.5.1/doc/Lazy.cpp.html0000644417616742025610000001406214064716023017314 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/Lazy.cpp.html

/***************************************************************************


Lazy<T>: template class for lazy initialization of objects whose
values do not change after initialization.
In a multi-threaded environment, this makes use of "double checked locking"
for an efficient, thread-safe solution.

Usage:

   Lazy<T> obj; // declaration of the lazy object

    ...

   do {
      Lazy<T>::Builder builder(obj);
      if (!builder()) break; // if we are not building, the break out

      UniquePtr<T> p;  // create a pointer 

         ...

      builder.move(p); // move p into the object to complete the initialization
                       // We can then complete the initialization process.
   } while(0);  // When this scope closes, the object is fully initialized.
                // subsequent attempts to build the object will yield
                // !builder.built()


   T objCopy = *obj;   // *obj returns a read-only reference
                       // one can also use -> operator

It is important to follow this recipe carefully.  In particular,
the builder must be enclosed in a scope, as it's destructor
plays a crucial role in finalizing the initialization.

NOTE: if p is null in builder.move(p), the object is still considered
built.

****************************************************************************/

template<class T, class P=DefaultDeleterPolicy>
class Lazy {
public:
   Lazy();

   Lazy(const Lazy&);
   Lazy& operator=(const Lazy&);
   // deep copies using T's copy constructor
   // EXCEPTIONS: may throw (but provides strong ES guarantee)

   const T& operator*()  const;     // pointer access
   const T* operator->() const;
   const T* get() const;

   operator fake_null_type() const;
   // allows test against 0

   ~Lazy();

   kill();  // destroy and reset

   bool built() const; // test if already built

   class Builder {
      Builder(const Lazy&);
     ~Builder()

      bool operator()() const; // test if we are building

      void move(UniquePtr<T,P>&);
      // EXCEPTIONS: may throw an exception if the move is not allowed
      // (i.e., not building or already moved).
      // Provides strong ES guarantee. 
   };
};


// EXCEPTIONS: except where noted, no exceptions are thrown

// NOTE: For more on double-checked locking, see
// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/

// NOTE: when compiled with the NTL_THREADS option, the Lazy
// class may contain data members from the standard library
// that may not satisfy the requirements of the Vec class
// (i.e., relocatability).  One can wrap it in a pointer 
// class (e.g., CopiedPtr) to deal with this.

// NOTE: The optional parameter P is used as in the specification
// of the UniquePtr class.  The default should work fine in 
// most cases.  It was introduced mainly to allow for the PIMPL
// paradigm.


ntl-11.5.1/doc/LazyTable.cpp.html0000644417616742025610000001246514064716023020271 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/LazyTable.cpp.html


/***************************************************************************


LazyTable<T,MAX>: template class for lazy initialization of objects whose
values do not change after initialization.  In a multi-threaded environment,
this makes use of "double checked locking" for an efficient, thread-safe
solution.

Usage:

   LazyTable<T,MAX> tab; // declaration of the lazy table, 
                         // with max size == MAX

    ...

   do {
      LazyTable<T,MAX>::Builder builder(tab, n); // request length n
      long amt = builder.amt();
      if (!amt) break;      

      ... initialize elements i = n-amt..n-1 
          using builder.move(p), where p is a UnqiuePtr<T>
          note that each move application appends one element
                             
   } while(0);    // When this scope closes, 
                  // the table is fully initialized to length n


   const T* val = table[i];  // read-only access to table elements 0..n-1
                             

It is important to follow this recipe carefully.  In particular,
the builder must be enclosed in a scope, as it's destructor
plays a crucial role in finalizing the initialization.

****************************************************************************/

template<class T, long MAX>
class LazyTable {
public:
   LazyTable();
   ~LazyTable();

   const T * const  operator[] (long i) const;
   // element access -- currently no range checking


   long length() const;
   // current table length

   class Builder {
      Builder(const LazyTable&, long request);
      // EXCEPTIONS: may throw an exception if request is out of range
      // or if alocation of table fails

     ~Builder()

      long amt() const;

      void move(UniquePtr<T>& p);
      // EXCEPTIONS: throws exception of move is not allowed.
      // Provides strong ES guarantee.
   };

private:
   LazyTable(const LazyTable&);             // disabled
   LazyTable& operator=(const LazyTable&);

};



// EXCEPTIONS: except where noted, no exceptions are thrown

// NOTE: For more on double-checked locking, see
// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/

// NOTE: when compiled with the NTL_THREADS option, the LazyTable
// class may contain data members from the standard library
// that may not satisfy the requirements of the Vec class
// (i.e., relocatability).  One can wrap it in a pointer 
// class (e.g., CopiedPtr) to deal with this.

ntl-11.5.1/doc/LLL.cpp.html0000644417616742025610000007054214064716023017025 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/LLL.cpp.html

/**************************************************************************\

MODULE: LLL

SUMMARY:

Routines are provided for lattice basis reduction, including both
exact-aritmetic variants (slow but sure) and floating-point variants
(fast but only approximate).

For an introduction to the basics of LLL reduction, see
[H. Cohen, A Course in Computational Algebraic Number Theory, Springer, 1993].

The LLL algorithm was introduced in [A. K. Lenstra, H. W. Lenstra, and
L. Lovasz, Math. Ann. 261 (1982), 515-534].

\**************************************************************************/




#include <NTL/mat_ZZ.h>



/**************************************************************************\

                         Exact Arithmetic Variants

\**************************************************************************/




long LLL(ZZ& det2, mat_ZZ& B, long verbose = 0);
long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

long LLL(ZZ& det2, mat_ZZ& B, long a, long b, long verbose = 0);
long LLL(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose = 0);


// performs LLL reduction.

// B is an m x n matrix, viewed as m rows of n-vectors.  m may be less
// than, equal to, or greater than n, and the rows need not be
// linearly independent.  B is transformed into an LLL-reduced basis,
// and the return value is the rank r of B.  The first m-r rows of B
// are zero.  

// More specifically, elementary row transformations are performed on
// B so that the non-zero rows of new-B form an LLL-reduced basis
// for the lattice spanned by the rows of old-B.
// The default reduction parameter is delta=3/4, which means
// that the squared length of the first non-zero basis vector
// is no more than 2^{r-1} times that of the shortest vector in
// the lattice.

// det2 is calculated as the *square* of the determinant
// of the lattice---note that sqrt(det2) is in general an integer
// only when r = n.

// In the second version, U is set to the transformation matrix, so
// that U is a unimodular m x m matrix with U * old-B = new-B.
// Note that the first m-r rows of U form a basis (as a lattice)
// for the kernel of old-B. 

// The third and fourth versions allow an arbitrary reduction
// parameter delta=a/b, where 1/4 < a/b <= 1, where a and b are positive
// integers.
// For a basis reduced with parameter delta, the squared length
// of the first non-zero basis vector is no more than 
// 1/(delta-1/4)^{r-1} times that of the shortest vector in the
// lattice (see, e.g., the article by Schnorr and Euchner mentioned below).

// The algorithm employed here is essentially the one in Cohen's book.


// Some variations:

long LLL_plus(vec_ZZ& D, mat_ZZ& B, long verbose = 0);
long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

long LLL_plus(vec_ZZ& D, mat_ZZ& B, long a, long b, long verbose = 0);
long LLL_plus(vec_ZZ& D, mat_ZZ& B, mat_ZZ& U, long a, long b,
              long verbose = 0);

// These are variations that return a bit more information about the
// reduced basis.  If r is the rank of B, then D is a vector of length
// r+1, such that D[0] = 1, and for i = 1..r, D[i]/D[i-1] is equal to
// the square of the length of the i-th vector of the Gram-Schmidt basis
// corresponding to the (non-zero) rows of the LLL reduced basis B.
// In particular, D[r] is equal to the value det2 computed by the
// plain LLL routines.

/**************************************************************************\

                      Computing Images and Kernels

\**************************************************************************/


long image(ZZ& det2, mat_ZZ& B, long verbose = 0);
long image(ZZ& det2, mat_ZZ& B, mat_ZZ& U, long verbose = 0);

// This computes the image of B using a "cheap" version of the LLL:
// it performs the usual "size reduction", but it only swaps
// vectors when linear dependencies are found.
// I haven't seen this described in the literature, but it works 
// fairly well in practice, and can also easily be shown
// to run in a reasonable amount of time with reasonably bounded
// numbers.

// As in the above LLL routines, the return value is the rank r of B, and the
// first m-r rows will be zero.  U is a unimodular m x m matrix with 
// U * old-B = new-B.  det2 has the same meaning as above.

// Note that the first m-r rows of U form a basis (as a lattice)
// for the kernel of old-B. 
// This is a reasonably practical algorithm for computing kernels.
// One can also apply image() to the kernel to get somewhat
// shorter basis vectors for the kernels (there are no linear
// dependencies, but the size reduction may anyway help).
// For even shorter kernel basis vectors, on can apply
// LLL(). 


/**************************************************************************\

                    Finding a vector in a lattice 

\**************************************************************************/

long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce=0);

// This tests if for given A and y, there exists x such that x*A = y;
// if so, x is set to a solution, and the value 1 is returned;
// otherwise, x is left unchanged, and the value 0 is returned.

// The optional parameter reduce controls the 'quality' of the
// solution vector;  if the rows of A are linearly dependent, 
// there are many solutions, if there are any at all.
// The value of reduce controls the amount of effort that goes
// into finding a 'short' solution vector x.

//    reduce = 0: No particular effort is made to find a short solution.

//    reduce = 1: A simple 'size reduction' algorithm is run on kernel(A);
//                this is fast, and may yield somewhat shorter
//                solutions than the default, but not necessarily
//                very close at all to optimal.

//    reduce = 2: the LLL algorithm is run on kernel(A);
//                this may be significantly slower than the other options,
//                but yields solutions that are provably close to optimal.
//                More precisely, if kernel(A) has rank k,
//                then the squared length of the obtained solution
//                is no more than max(1, 2^(k-2)) times that of 
//                the optimal solution.  This makes use of slight
//                variation of Babai's approximately nearest vector algorithm.

// Of course, if the the rows of A are linearly independent, then
// the value of reduce is irrelevant: the solution, if it exists,
// is unique.

// Note that regardless of the value of reduce, the algorithm
// runs in polynomial time, and hence the bit-length of the solution
// vector is bounded by a polynomial in the bit-length of the inputs.




/**************************************************************************\

                   Floating Point Variants

There are a number of floating point LLL variants available:
you can choose the precision, the orthogonalization strategy,
and the reduction condition.

The wide variety of choices may seem a bit bewildering.
See below the discussion "How to choose?".

*** Precision:

  FP -- double
  QP -- quad_float (quasi quadruple precision)
        this is useful when roundoff errors can cause problems
  XD -- xdouble (extended exponent doubles)
        this is useful when numbers get too big
  RR -- RR (arbitrary precision floating point)
        this is useful for large precision and magnitudes

  Generally speaking, the choice FP will be the fastest,
  but may be prone to roundoff errors and/or overflow.
  

*** Orthogonalization Strategy: 

  -- Classical Gramm-Schmidt Orthogonalization.
     This choice uses classical methods for computing
     the Gramm-Schmidt othogonalization.
     It is fast but prone to stability problems.
     This strategy was first proposed by Schnorr and Euchner
     [C. P. Schnorr and M. Euchner, Proc. Fundamentals of Computation Theory, 
     LNCS 529, pp. 68-85, 1991].  
     The version implemented here is substantially different, improving
     both stability and performance.

  -- Givens Orthogonalization.
     This is a bit slower, but generally much more stable,
     and is really the preferred orthogonalization strategy.
     For a nice description of this, see Chapter 5 of  
     [G. Golub and C. van Loan, Matrix Computations, 3rd edition,
     Johns Hopkins Univ. Press, 1996].


*** Reduction Condition:

  -- LLL: the classical LLL reduction condition.

  -- BKZ: Block Korkin-Zolotarev reduction.
     This is slower, but yields a higher-quality basis,
     i.e., one with shorter vectors.
     See the Schnorr-Euchner paper for a description of this.
     This basically generalizes the LLL reduction condition
     from blocks of size 2 to blocks of larger size.


************* Calling Syntax for LLL routines ***************

long 
[G_]LLL_{FP,QP,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta = 0.99, 
                       long deep = 0, LLLCheckFct check = 0, long verbose = 0);

* The [ ... ] notation indicates something optional,
  and the { ... } indicates something that is chosen from
  among several alternatives.

* The return value is the rank of B (but see below if check != 0).

* The optional prefix G_ indicates that Givens rotations are to be used;
  otherwise, classical Gramm-Schmidt is used.

* The choice FP, QP, XD, RR determines the precision used.

* If the optional parameter U is given, then U is computed
  as the transition matrix:

     U * old_B = new_B

* The optional argument "delta" is the reduction parameter, and may
  be set so that 0.50 <= delta < 1.  Setting it close to 1 yields
  shorter vectors, and also improves the stability, but increases the
  running time.  Recommended value: delta = 0.99.

* The optional parameter "deep" can be set to any positive integer,
  which allows "deep insertions" of row k into row i, provided i <=
  deep or k-i <= deep.  Larger values of deep will usually yield
  shorter vectors, but the running increases exponentially.  

  NOTE: use of "deep" is obsolete, and has been "deprecated".
  It is recommended to use BKZ_FP to achieve higher-quality reductions.
  Moreover, the Givens versions do not support "deep", and setting
  deep != 0 will raise an error in this case.

* The optional parameter "check" is a function that is invoked after
  each size reduction with the current row as an argument.  If this
  function returns a non-zero value, the LLL procedure is immediately
  terminated.  Note that it is possible that some linear dependencies
  remain undiscovered, so that the calculated rank value is in fact
  too large.  In any case, zero rows discovered by the algorithm
  will be placed at the beginning, as usual.

  The check argument (if not zero) should be a routine taking
  a const vec_ZZ& as an argument and return value of type long.
  LLLCheckFct is defined via a typedef as:

     typedef long (*LLLCheckFct)(const vec_ZZ&);

  See the file subset.cpp for an example of the use of this feature.

* The optional parameter "verbose" can be set to see all kinds of fun
  things printed while the routine is executing.  A status report is
  printed every once in a while, and the current basis is optionally
  dumped to a file.  The behavior can be controlled with these global
  variables:

     extern thread_local char *LLLDumpFile;  
     // file to dump basis, 0 => no dump; 
     // initially 0

     extern thread_local double LLLStatusInterval; 
     // seconds between status reports 
     // initially 900s = 15min

 
************* Calling Syntax for BKZ routines ***************

long 
[G_]BKZ_{FP,QP,QP1,XD,RR} (mat_ZZ& B, [ mat_ZZ& U, ] double delta=0.99,
                          long BlockSize=10, long prune=0, 
                          LLLCheckFct check = 0, long verbose = 0);

These functions are equivalent to the LLL routines above,
except that Block Korkin-Zolotarev reduction is applied.
We describe here only the differences in the calling syntax.

* The optional parameter "BlockSize" specifies the size of the blocks
  in the reduction.  High values yield shorter vectors, but the
  running time increases exponentially with BlockSize.
  BlockSize should be between 2 and the number of rows of B.

* The optional parameter "prune" can be set to any positive number to
  invoke the Volume Heuristic from [Schnorr and Horner, Eurocrypt
  '95].  This can significantly reduce the running time, and hence
  allow much bigger block size, but the quality of the reduction is
  of course not as good in general.  Higher values of prune mean
  better quality, and slower running time.  
  When prune == 0, pruning is disabled.
  Recommended usage: for BlockSize >= 30, set 10 <= prune <= 15.

* The QP1 variant uses quad_float precision to compute Gramm-Schmidt,
  but uses double precision in the search phase of the block reduction
  algorithm.  This seems adequate for most purposes, and is faster
  than QP, which uses quad_float precision uniformly throughout.


******************** How to choose? *********************

I think it is safe to say that nobody really understands
how the LLL algorithm works.  The theoretical analyses are a long way
from describing what "really" happens in practice.  Choosing the best
variant for a certain application ultimately is a matter of trial
and error.

The first thing to try is LLL_FP.
It is the fastest of the routines, and is adequate for many applications.

If there are precision problems, you will most likely get
a warning message, something like "warning--relaxing reduction".
If there are overflow problems, you should get an error message
saying that the numbers are too big.

If either of these happens, the next thing to try is G_LLL_FP,
which uses the somewhat slower, but more stable, Givens rotations.
This approach also has the nice property that the numbers remain
smaller, so there is less chance of an overflow.

If you are still having precision problems with G_LLL_FP,
try LLL_QP or G_LLL_QP, which uses quadratic precision.

If you are still having overflow problems, try LLL_XD or G_LLL_XD.

I haven't yet come across a case where one *really* needs the
extra precision available in the RR variants.

All of the above discussion applies to the BKZ variants as well.
In addition, if you have a matrix with really big entries, you might try 
using G_LLL_FP or LLL_XD first to reduce the sizes of the numbers,
before running one of the BKZ variants.

Also, one shouldn't rule out using the "all integer" LLL routines.
For some highly structured matrices, this is not necessarily
much worse than some of the floating point versions, and can
under certain circumstances even be better.


******************** Implementation notes *********************

For all the floating point variants, I use a "relaxed" size reduction
condition.  Normally in LLL one makes all |\mu_{i,j}| <= 1/2.
However, this can easily lead to infinite loops in floating point arithemetic.
So I use the condition |\mu_{i,j}| <= 1/2 + fudge, where fudge is 
a very small number.  Even with this, one can fall into an infinite loop.
To handle this situation, I added some logic that detects, at quite low cost,
when an infinite loop has been entered.  When that happens, fudge
is replaced by fudge*2, and a warning message "relaxing reduction condition"
is printed.   We may do this relaxation several times.
If fudge gets too big, we give up and abort, except that 
LLL_FP and BKZ_FP make one last attempt to recover:  they try to compute the
Gramm-Schmidt coefficients using RR and continue.  As described above,
if you run into these problems, which you'll see in the error/warning
messages, it is more effective to use the QP and/or Givens variants.

For the Gramm-Schmidt orthogonalization, lots of "bookeeping" is done
to avoid computing the same thing twice.

For the Givens orthogonalization, we cannot do so many bookeeping tricks.
Instead, we "cache" a certain amount of information, which
allows us to avoid computing certain things over and over again.

There are many other hacks and tricks to speed things up even further.
For example, if the matrix elements are small enough to fit in
double precision floating point, the algorithms avoid almost
all big integer arithmetic.  This is done in a dynamic, on-line
fashion, so even if the numbers start out big, whenever they
get small, we automatically switch to floating point arithmetic.

\**************************************************************************/




/**************************************************************************\

                         Other Stuff

\**************************************************************************/



void ComputeGS(const mat_ZZ& B, mat_RR& mu, vec_RR& c);

// Computes Gramm-Schmidt data for B.  Assumes B is an m x n matrix of
// rank m.  Let if { B^*(i) } is the othogonal basis, then c(i) =
// |B^*(i)|^2, and B^*(i) = B(i) - \sum_{j=1}^{i-1} mu(i,j) B^*(j).

void NearVector(vec_ZZ& w, const mat_ZZ& B, const vec_ZZ& a);

// Computes a vector w that is an approximation to the closest vector
// in the lattice spanned by B to a, using the "closest plane"
// algorithm from [Babai, Combinatorica 6:1-13, 1986].  B must be a
// square matrix, and it is assumed that B is already LLL or BKZ
// reduced (the better the reduction the better the approximation).
// Note that arithmetic in RR is used with the current value of
// RR::precision().

// NOTE: Both of these routines use classical Gramm-Schmidt
// orthogonalization.


ntl-11.5.1/doc/RR.cpp.html0000644417616742025610000011323414064716023016721 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/RR.cpp.html

/**************************************************************************\

MODULE: RR

SUMMARY:

The class RR is used to represent arbitrary-precision floating point
numbers.

The functions in this module guarantee very strong accuracy conditions
which make it easy to reason about the behavior of programs using
these functions.

The arithmetic operations always round their results to p bits, where
p is the current precision.  The current precision can be changed
using RR::SetPrecision(), and can be read using RR::precision().  

The minimum precision that can be set is 53 bits.
The maximum precision is limited only by the word size of the machine.

A convenience class RRPush is provided to automatically save and
restore the current precision.

All arithmetic operations are implemented so that the effect is as if the
result was computed exactly, and then rounded to p bits.  If a number
lies exactly half-way between two p-bit numbers, the "round to even"
rule is used.  So in particular, the computed result will have a relative error
of at most 2^{-p}.


The above rounding rules apply to all arithmetic operations in this
module, except for the following routines:

* The transcendental functions: 
     log, exp, log10, expm1, log1p, pow, sin, cos, ComputePi

* The power function

* The input and ascii to RR conversion functions when using "e"-notation 

For these functions, a very strong accuracy condition is still 
guaranteed: the computed result has a relative error of less than 2^{-p + 1}
(and actually much closer to 2^{-p}).
That is, it is as if the resulted were computed exactly, and then
rounded to one of the two neighboring p-bit numbers (but not necessarily
the closest).

The behavior of all functions in this module is completely platform 
independent: you should get *exactly* the same results on any platform
(the only exception to this rule is the random number generator).

Note that because precision is variable, a number may be computed with
to a high precision p', and then be used as input to an arithmetic operation
when the current precision is p < p'.  
The above accuracy guarantees still apply; in particular, 
no rounding is done until *after* the operation is performed.  

EXAMPLE: If x and y are computed to 200 bits of precision,
and then the precision is set to 100 bits, then x-y will
be computed correctly to 100 bits, even if, say, x and y agree
in their high-order 50 bits.  If x and y had been rounded to
100 bits before the subtraction, then the difference would
only be accurate to 50 bits of precision.

Note that the assignment operator and the copy constructor 
produce *exact* copies of their inputs---they are *never* rounded. 
This is a change in semantics from versions 2.0 and earlier
in which assignment and copy rounded their outputs.
This was deemed a design error and has been changed.

If you want to force rounding to current precision, the easiest
way to do this is with the RR to RR conversion routines:
   conv(x, a);
or
   x = to_RR(a); 
This will round a to current precision and store the result in x.
Note that writing
   x = a + 0;
or
   x = a*1;
also has the same effect.

Unlike IEEE standard floating point, there are no "special values",
like "infinity" or "not a number", nor are there any "denormalized
numbers".  Overflow, underflow, or taking a square root of a negative
number all result in an error being raised.

An RR is represented as a mantissa/exponent pair (x, e), where x is a
ZZ and e is a long.  The real number represented by (x, e) is x * 2^e.
Zero is always represented as (0, 0).  For all other numbers, x is
always odd.


CONVERSIONS AND PROMOTIONS:
The complete set of conversion routines between RR and other types is
documented in the file "conversions.txt". Conversion from any type
to RR always rounds the result to the current precision.

The basic operations also support the notion of "promotions", 
so that they promote a double to an RR.  For example, one can write 
   x = y + 1.5;
where x and y are RR's. One should be aware that these promotions are 
always implemented using the double to RR conversion routine.


SIZE INVARIANT: max(NumBits(x), |e|) < 2^(NTL_BITS_PER_LONG-4)

\**************************************************************************/




#include <NTL/ZZ.h>
#include <NTL/xdouble.h>
#include <NTL/quad_float.h>

class RR {

public:

RR(); // = 0

RR(const RR& a); // copy constructor


explicit RR(double a);  // promotion constructor

RR& operator=(const RR& a); // assignment operator

// NOTE: the copy constructor and assignment operator
// produce exact copies of their inputs, and do not round
// to current precision.  

RR& operator=(double a); // convert and assign

~RR(); // destructor

RR(RR&& a);
// move constructor (C++11 only)
// declared noexcept unless NTL_EXCEPTIONS flag is set

RR& operator=(RR&& a);
// move assignment (C++11 only)
// declared noexcept unless NTL_EXCEPTIONS flag is set

const ZZ& mantissa() const;  // read the mantissa
long exponent() const;  // read the exponent

static void SetPrecision(long p);
// set current precision to max(p, 53) bits.
// The default is 150

static long precision();  // read current value of precision

static void SetOutputPrecision(long p);
// set the number of output decimal digits to max(p, 1).
// The default is 10

static long OutputPrecision();
// read the current number of output decimal digits


};



/**************************************************************************\

                                  Comparison

\**************************************************************************/



// standard comparison operators:

long operator==(const RR& a, const RR& b);
long operator!=(const RR& a, const RR& b);
long operator<=(const RR& a, const RR& b);
long operator>=(const RR& a, const RR& b);
long operator <(const RR& a, const RR& b);
long operator >(const RR& a, const RR& b);


long IsZero(const RR& a); // test if 0
long IsOne(const RR& a); // test if 1

long sign(const RR& a);  // returns sign of a (+1, -1, 0)
long compare(const RR& a, const RR& b); // returns sign(a-b);

// PROMOTIONS: operators ==, ..., > and function compare
// promote double to RR on (a, b).



/**************************************************************************\

                                  Addition

\**************************************************************************/

// operator notation:

RR operator+(const RR& a, const RR& b);
RR operator-(const RR& a, const RR& b);
RR operator-(const RR& a); // unary -

RR& operator+=(RR& x, const RR& a);
RR& operator+=(RR& x, double a);

RR& operator-=(RR& x, const RR& a);
RR& operator-=(RR& x, double a);

RR& operator++(RR& x);  // prefix
void operator++(RR& x, int);  // postfix

RR& operator--(RR& x);  // prefix
void operator--(RR& x, int);  // postfix


// procedural versions:

void add(RR& z, const RR& a, const RR& b); // z = a+b
void sub(RR& z, const RR& a, const RR& b); // z = a-b
void negate(RR& z, const RR& a); // z = -a

// PROMOTIONS: operators +, -, and procedures add, sub promote double
// to RR on (a, b).

void abs(RR& z, const RR& a); // z = |a|
RR fabs(const RR& a);
RR abs(const RR& a);


/**************************************************************************\

                                  Multiplication

\**************************************************************************/


// operator notation:

RR operator*(const RR& a, const RR& b);

RR& operator*=(RR& x, const RR& a);
RR& operator*=(RR& x, double a);

// procedural versions:


void mul(RR& z, const RR& a, const RR& b); // z = a*b

void sqr(RR& z, const RR& a); // z = a * a
RR sqr(const RR& a);

// PROMOTIONS: operator * and procedure mul promote double to RR on (a, b).


/**************************************************************************\

                               Division

\**************************************************************************/


// operator notation:

RR operator/(const RR& a, const RR& b);

RR& operator/=(RR& x, const RR& a);
RR& operator/=(RR& x, double a);


// procedural versions:


void div(RR& z, const RR& a, const RR& b); z = a/b

void inv(RR& z, const RR& a); // z = 1 / a
RR inv(const RR& a);

// PROMOTIONS: operator / and procedure div promote double to RR on (a, b).



/**************************************************************************\

                       Transcendental functions 

\**************************************************************************/


void exp(RR& res, const RR& x);  // e^x
RR exp(const RR& x);

void log(RR& res, const RR& x); // log(x) (natural log)
RR log(const RR& x);

void log10(RR& res, const RR& x); // log(x)/log(10)
RR log10(const RR& x);

void expm1(RR& res, const RR&  x);
RR expm1(const RR& x);
// e^(x)-1; more accurate than exp(x)-1 when |x| is small

void log1p(RR& res, const RR& x);
RR log1p(const RR& x);
// log(1 + x); more accurate than log(1 + x) when |x| is small

void pow(RR& res, const RR& x, const RR& y);  // x^y
RR pow(const RR& x, const RR& y);

void sin(RR& res, const RR& x);  // sin(x); restriction: |x| < 2^1000
RR sin(const RR& x);

void cos(RR& res, const RR& x);  // cos(x); restriction: |x| < 2^1000
RR cos(const RR& x);

void ComputePi(RR& pi); // approximate pi to current precision
RR ComputePi_RR();


/**************************************************************************\

                         Rounding to integer values        

\**************************************************************************/


/*** RR output ***/

void trunc(RR& z, const RR& a);  // z = a, truncated to 0
RR trunc(const RR& a);

void floor(RR& z, const RR& a);  // z = a, truncated to -infinity
RR floor(const RR& a);

void ceil(RR& z, const RR& a);   // z = a, truncated to +infinity
RR ceil(const RR& a);

void round(RR& z, const RR& a);   // z = a, truncated to nearest integer
RR round(const RR& a);            // ties are rounded to an even integer



/*** ZZ output ***/

void TruncToZZ(ZZ& z, const RR& a);  // z = a, truncated to 0
ZZ TruncToZZ(const RR& a);

void FloorToZZ(ZZ& z, const RR& a);  // z = a, truncated to -infinity
ZZ FloorToZZ(const RR& a);           // same as RR to ZZ conversion

void CeilToZZ(ZZ& z, const RR& a);   // z = a, truncated to +infinity
ZZ CeilToZZ(const ZZ& a);

void RoundToZZ(ZZ& z, const RR& a);   // z = a, truncated to nearest integer
ZZ RoundToZZ(const RR& a);            // ties are rounded to an even integer





/**************************************************************************\

                 Saving and restoring the current precision

\**************************************************************************/


class RRPush {
public:
   RRPush();  // saves the cuurent precision
   ~RRPush(); // restores the saved precision

private:
   RRPush(const RRPush&); // disable
   void operator=(const RRPush&); // disable
};


// Example: 
//
// {
//    RRPush push;  // don't forget to declare a variable!!
//    RR::SetPrecsion(new_p);
//    ...
// } // old precsion restored when scope is exited


class RROutputPush {
public:
   RROutputPush();   // saves the cuurent output precision
   ~RROutputPush();  // restores the saved output precision

private:
   RROutputPush(const RROutputPush&); // disable
   void operator=(const RROutputPush&); // disable
};


// Example: 
//
// {
//    RROutputPush push;  // don't forget to declare a variable!!
//    RR::SetOutputPrecsion(new_op);
//    ...
// } // old output precsion restored when scope is exited




/**************************************************************************\

                                 Miscelaneous

\**************************************************************************/


void MakeRR(RR& z, const ZZ& a,  long e);
RR MakeRR(const ZZ& a,  long e);
// z = a*2^e, rounded to current precision

void random(RR& z);
RR random_RR();
// z = pseudo-random number in the range [0,1).
// Note that the behaviour of this function is somewhat platform
// dependent, because the underlying pseudo-ramdom generator is.


void SqrRoot(RR& z, const RR& a); // z = sqrt(a);
RR SqrRoot(const RR& a);
RR sqrt(const RR& a);

void power(RR& z, const RR& a, long e); // z = a^e, e may be negative
RR power(const RR& a, long e);

void power2(RR& z, long e); // z = 2^e, e may be negative
RR power2_RR(long e);


void clear(RR& z);  // z = 0
void set(RR& z);  // z = 1

void RR::swap(RR& a);
void swap(RR& a, RR& b);
// swap (pointer swap)



/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5 5.  -.5  e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine RR::SetOutputPrecision(p).  The default value of p is 10.
The current value of p is returned by a call to RR::OutputPrecision().


\**************************************************************************/



ostream& operator<<(ostream& s, const RR& a);
istream& operator>>(istream& s, RR& x);

/**************************************************************************\


            Specialized routines with explicit precision parameter

These routines take an explicit precision parameter p.  The value of p may be
any positive integer.  All results are computed to *precisely* p bits of
precision, regardless of the current precision (as set by RR::SetPrecision).

These routines are provided both for convenience and for situations where the
computation must be done with a precision that may be less than 53.


\**************************************************************************/




void AddPrec(RR& z, const RR& a, const RR& b, long p); // z = a + b
RR AddPrec(const RR& a, const RR& b, long p);

void SubPrec(RR& z, const RR& a, const RR& b, long p); // z = a - b
RR SubPrec(const RR& a, const RR& b, long p);

void NegatePrec(RR& z, const RR& a, long p); // z = -a
RR NegatePrec(const RR& a, long p);

void AbsPrec(RR& z, const RR& a, long p); // z = |a|
RR AbsPrec(const RR& a, long p);

void MulPrec(RR& z, const RR& a, const RR& b, long p); // z = a*b
RR MulPrec(const RR& a, const RR& b, long p);

void SqrPrec(RR& z, const RR& a, long p); // z = a*a
RR SqrPrec(const RR& a, long p);

void DivPrec(RR& z, const RR& a, const RR& b, long p);  // z = a/b
RR DivPrec(const RR& a, const RR& b, long p);

void InvPrec(RR& z, const RR& a, long p);  // z = 1/a
RR DivPrec(const RR& a, long p);

void SqrRootPrec(RR& z, const RR& a, long p); // z = sqrt(a)
RR SqrRootPrec(const RR& a, long p);

void TruncPrec(RR& z, const RR& a, long p); // z = a, truncated to 0
RR TruncPrec(const RR& a, long p);

void FloorPrec(RR& z, const RR& a, long p); // z = a, truncated to -infinity
RR FloorPrec(const RR& a, long p);

void CeilPrec(RR& z, const RR& a, long p);  // z = a, truncated to +infinity
RR CeilPrec(const RR& a, long p);

void RoundPrec(RR& z, const RR& a, long p); // z = a, 
                                            // truncated to nearest integer,
                                            // ties are roundec to an even 
                                            // integer
RR RoundPrec(const RR& a, long p);

void ConvPrec(RR& z, const RR& a, long p); // z = a
RR ConvPrec(const RR& a, long p);

void ConvPrec(RR& z, const ZZ& a, long p); // z = a
RR ConvPrec(const ZZ& a, long p);

void ConvPrec(RR& z, long a, long p); // z = a
RR ConvPrec(long a, long p);

void ConvPrec(RR& z, int a, long p); // z = a
RR ConvPrec(int a, long p);

void ConvPrec(RR& z, unsigned long a, long p); // z = a
RR ConvPrec(unsigned long a, long p);

void ConvPrec(RR& z, unsigned int a, long p); // z = a 
RR ConvPrec(unsigned int a, long p);

void ConvPrec(RR& z, double a, long p); // z = a
RR ConvPrec(double a, long p);

void ConvPrec(RR& z, const xdouble& a, long p); // z = a
RR ConvPrec(const xdouble& a, long p);

void ConvPrec(RR& z, const quad_float& a, long p); // z = a
RR ConvPrec(const quad_float& a, long p);

void ConvPrec(RR& z, const char *s, long p); // read z from s
RR ConvPrec(const char *s, long p);

istream& InputPrec(RR& z, istream& s, long p);  // read z from s
RR InputPrec(istream& s, long p);
// The functional variant raises an error if input
// is missing or ill-formed, while procedural form
// does not.

void MakeRRPrec(RR& z, const ZZ& a, long e, long p); // z = a*2^e
RR MakeRRPrec(const ZZ& a, long e, long p);


/**************************************************************************\

COMPATABILITY NOTES: 

 (1)  Prior to version 5.3, the documentation indicated that under certain
      circumstances, the value of the current precision could be directly set
      by setting the variable RR::prec.  Such usage is now considered
      obsolete.  To perform computations using a precision of less than 53
      bits, users should use the specialized routines AddPrec, SubPrec, etc.,
      documented above.

 (2)  The routine RoundToPrecision is obsolete, although for backward
      compatability, it is still declared (in both procedural and function
      forms), and is equivalent to ConvPrec.

 (3)  In versions 2.0 and earlier, the assignment operator and copy
      constructor for the class RR rounded their outputs to the current
      precision.  This is no longer the case:  their outputs are now exact
      copies of their inputs, regardless of the current precision.

\**************************************************************************/


ntl-11.5.1/doc/SmartPtr.cpp.html0000644417616742025610000015447114064716023020162 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/SmartPtr.cpp.html


/****************************************************************************

SmartPtr: a smart pointer class.

Synopsis: provides a reference counted smart pointer, similar to shared_ptr
in the standard library.  It is provided here to minimize reliance
on the standard library, especially for older C++ compilers, which may
not provide shared_ptr, or it may be in TR1, which gets messy.


Examples:


  SmartPtr<T> p1;         // initialize to null
  SmartPtr<T> p1(0); 

  SmartPtr<T> p2 = 0;     // 0/nullptr implicitly converts to SmartPtr<T>

  SmartPtr<T> p3(p1);     // copy constructor

  T *rp;
  SmartPtr<T> p4(rp);     // construct using raw pointer (explicit): better 
                          // to use MakeSmart below

  p1 = MakeSmart<T>(...); // build new T object by invoking constructor
                          // T(...) with pseudo-variadic templates.
                          // This is safer and more efficient that
                          // using the raw-pointer constructor
                        
  p1 = p2;                // assignment
  p1 = 0;                 // assign null


  if (!p1) ...            //  test for null
  if (p1 == 0) ... 

  if (p1) ...             // test for not null ... 
  if (p1 != 0) ... 

  if (p1 == p2) ...       // test for equality 
  if (p1 != p2) 

  *p1                     // dereferencing
  p1->...

  p1.get();               // return the underlying raw pointer...dangerous!

  p1.swap(p2);            // fast swap
  swap(p1, p2);


Automatic Conversions:

If S is another class, SmartPtr<S> converts to SmartPtr<T> if S* converts to T*
(for example, if S is a subclass of T).  Similarly, SmartPtr<S> and SmartPtr<T>
may be compared if S* and T* may be compared.

0/nullptr automatically converts to SmartPtr<T>.

MakeSmart:

One can write SmartPtr<T> p = MakeSmart<T>(x1, ..., xn), and this will create a
smart pointer to an object constructed as T(x1, ..., xn).  Besides notational
convenience, it also reduces the number of memory allocations from 2 to 1, as
the data and control block can be allocated in one chunck of memory.

In C++11 mode, this is implemented using variadic templates and "perfect
forwarding".  Otherwise, this is implemented using macros, and there are some
limitations: first, the number n of arguments is limited to 9; second, all
arguments are pass by const reference, but you can work around this by using
the helper function Fwd.  For example, if T has a 2-argument constructor where
the second must be a non-const reference of some type, and x2 is a variable of
that type, you can write MakeSmart<T>(x1, Fwd(x2)), to forward that reference
through in a typesafe manner.  Note that for compatibility, the Fwd function is
also available in C++11 mode, so you can write code that will work in either
mode.

MakeRaw:

One can also write T *p = MakeRaw<T>(x1, ..., xn) to create a 
raw pointer.  This is the same as writing T *p = new T(x1, ..., xn),
except that error handling is determined by the NTL_EXCEPTION
flag (on => bad_alloc exception is thrown, off => error message
and abort).

MakeRawArray:

Another utility routine: one can write T *p = MakeRawArray<T>(n)
to make a plain array of n T objects.  Error handling is the same
as for MakeRaw.

Dynamic casting:

I've also supplied a dynamic cast operation for smart pointers.

   SmartPtr<Derived> d = MakeSmart<Derived>(); // d points to Derived
   SmartPtr<Base> b = d; // implicit upcast: OK

   SmartPtr<Derived> d1 = DynamicCast<Derived>(b);
      // downcast to a Derived object -- returns null for a bad cast

DeleterPolicy:

Normally, when the object pointed to a SmartPtr needs to be destroyed, this is
done by invoking delete on the raw pointer.  The user can override this
behavior by specifying a "deleter policy", which is a class P that defines a
static member function deleter, which is invoked as P::deleter(p).  Such a
policy can be attached to a SmartPtr using a specialized constructor (see
below).

A deleter policy can be useful, for example, in realizing the PIPL
pattern, where the class T's definition is not visible.  The specified deleter
can invoke a free-standing function that itself invokes delete.  A deleter
policy can also be useful is memory is to be managed using some mechanism other
than new/delete.


Implementation notes:

If NTL is compiled with the NTL_THREADS option, then the reference counting
will be thread safe.

The SmartPtrControl class heirarchy is used to make sure the right destructor
is called when the ref count goes to zero.  This can be an issue for forward
declared classes and for subclasses.  For example, if T is forward declared in
a context where the ref count goes to zero, or if the object's actual type is a
subclass of T and T's destructor was not declared virtual.  The implementation
of SmartPtr guarantees correct behavior in these situations.

The null tests p, !p, p == 0, are all effected via an implicit conversion from
SmartPtr<T> to a funny pointer type (a pointer to a member function, which
avoids other, unwanted implicit conversions: this is the so-called "safe bool
idiom");

Also, there is an implicit conversion from another funny pointer type to
SmartPtr<T>, which is how the implicit conversion from 0/nullptr is achieved.

In C++11 both of the above effects could perhaps be achieved more directly.
The new "explict bool" operator can replace the "safe bool idiom", and 
the new nullptr_t type could be used to get the conversion from null to work.

NOTES: See http://www.artima.com/cppsource/safebool.html for more on the "safe
bool idiom".  


*****************************************************************************/

// The default "deleter policy"
struct DefaultDeleterPolicy {

   template<class T>
   static void deleter(T *p) { delete p; }

};

// A tagging class, for better readability in invoking constructor.
// Usage: SmartPtr<T> p(r, ChoosePolicy<MyDeleterPolicy>());
template<class P>
struct ChoosePolicy { };





template<class T>
class SmartPtr {
public:
public:
   template<class Y> explicit SmartPtr(Y* p);
   // construct smart pointer from raw pointer with deleter policy
   // DefaultDeleterPolicy (so p should be allocated using new).

   // NOTE: Y* must convert to T*, but upon the original pointer is preserved
   // so that when ref count drops to 0, the *original* object of type Y is destroyed.

   // EXCEPTIONS: a control block is dynamically allocated;
   //    if this allocation fails, the object pointed to by p is destroyed
   //    and a bad_alloc exception is thrown

   template<class Y, class P> SmartPtr(Y* p, ChoosePolicy<P>);
   // construct smart pointer from raw pointer with deleter policy P.

   // NOTE: Y* must convert to T*, but upon the original pointer is preserved
   // so that when ref count drops to 0, the *original* object of type Y is destroyed.

   // EXCEPTIONS: a control block is dynamically allocated;
   //    if this allocation fails, the object pointed to by p is destroyed
   //    and a bad_alloc exception is thrown

   SmartPtr();
   // initial value null

   SmartPtr(fake_null_type1);
   // automatic conversion from 0/nullptr

   ~SmartPtr();
   // destructor

   SmartPtr(const SmartPtr& other);
   SmartPtr& operator=(const SmartPtr& other);
   // copy and assignment

   template<class Y> SmartPtr(const SmartPtr<Y>& other);
   template<class Y> SmartPtr& operator=(const SmartPtr<Y>& other);
   // copy and assignment

   SmartPtr(SmartPtr&& other) noexcept;
   SmartPtr& operator=(SmartPtr&& other) noexcept;
   // move semantics (C++11 only)

   template<class Y> SmartPtr(SmartPtr<Y>&& other) noexcept;
   template<class Y> SmartPtr& operator=(SmartPtr<Y>&& other);
   // move semantics (C++11 only)

   T& operator*()  const;
   T* operator->() const;
   // indirection

   T* get() const;
   // get underlying raw pointer

   void swap(SmartPtr& other);

   SmartPtr(fake_null_type);
   // allows assignment and initialization from 0

   operator fake_null_type() const;
   // allows comparisons to 0

   template<class Y> SmartPtr<Y> DynamicCast() const;
};


// free swap function
template<class T> void swap(SmartPtr<T>& p, SmartPtr<T>& q);

// free dynamic cast function
template<class X, class Y> SmartPtr<X> DynamicCast(const SmartPtr<Y>& p);


// Equality testing
template<class X, class Y>
bool operator==(const SmartPtr<X>& a, const SmartPtr<Y>& b);

template<class X, class Y>
bool operator!=(const SmartPtr<X>& a, const SmartPtr<Y>& b);

// MakeSmart variadic template
template<class T, class... Args>
SmartPtr<T> MakeSmart(Args&&... args);
// EXCEPTIONS: may throw an exception if constructor for T throws
// or memory allocation fails


// EXCEPTIONS: unless otherwise specified, the methods above
// never throw an exception (under C++11 rules, if a destructor
// is invoked that throws an exception, the program will terminate).


/****************************************************************************

Experimantal: CloneablePtr<T> ...essentially same interface as SmartPtr, but 
allows cloning of complete objects.  The differences:
*  must construct using MakeCloneable
*  a clone method is provided
*  implicit conversion from CloneablePtr to SmartPtr is allowed

Example:

   CloneablePtr<Derived> d = MakeCloneable<Derived>(); 
   // d points to Derived

   CloneablePtr<Base> b = d; // implicit upcast: OK

   CloneablePtr<Base> b1 = b.clone(); 
   // clone of b, which is really a Derived object

   CloneablePtr<Derived> d1 = DynamicCast<Derived>(b1);
   // downcast to a Derived object -- returns null for a bad cast

   SmartPtr<Base> b2 = d1;
   


Implementation:

In the clone method, the object is constructed using the copy constructor for
the type T, where T is the compile-time type with which the first smart pointer
to this object was was created, even if the pointer has been subsequently
upcasted to a base type S.  Such objects must have been initially created using
the MakeCloneable function.  It turns out, this is hard to do in a completely
standards-compliant way, because of the type erasure going on.  So I settled on
the current method, which does some low-level pointer arithmetic.  Even with
fancy things like multiple and virtual inheritance, it should work, under the
assumption that if two objects have the same (runtime) type, then their memory
layout is the same.  I don't think anything like that is guaranteed by the
standard, but this seems reasonable, and it seems to work.  Like I said, it is
experimental, and I would appreciate feedback from C++ gurus.

Note that NTL does not use this feature, but I do have applications where this
is convenient.


**********************************************************************************/


template<class T>
class CloneablePtr {
public:
   CloneablePtr();
   // initial value null

   ~CloneablePtr();
   // if ref count drops to zero, then delete referent

   CloneablePtr(const CloneablePtr& other);
   CloneablePtr& operator=(const CloneablePtr& other);
   // copy and assignment

   template<class Y> CloneablePtr(const CloneablePtr<Y>& other);
   template<class Y> CloneablePtr& operator=(const CloneablePtr<Y>& other);
   // copy and assignment

   CloneablePtr(CloneablePtr&& other) noexcept;
   CloneablePtr& operator=(CloneablePtr&& other) noexcept;
   // move semantics (C++11 only)

   template<class Y> CloneablePtr(CloneablePtr<Y>&& other) noexcept;
   template<class Y> CloneablePtr& operator=(CloneablePtr<Y>&& other);
   // move semantics (C++11 only)

   T& operator*()  const;
   T* operator->() const;
   // indirection

   T* get() const;
   // get underlying raw pointer

   void swap(CloneablePtr& other);

   CloneablePtr(fake_null_type);
   // allows assignment and initialization from 0

   operator fake_null_type() const;
   // allows comparisons to 0

   template<class Y> CloneablePtr<Y> DynamicCast() const;

   CloneablePtr clone() const;
   // construct a clone, using the copy constructor
   // EXCEPTIONS: may throw if copy construction fails


   template<class Y> operator SmartPtr<Y>();
   // implicit conversion from CloneablePtr<T> to SmartPtr<Y>,
   // allowed if T* converts implicitly to Y*.
};


// free swap function
template<class T> void swap(CloneablePtr<T>& p, CloneablePtr<T>& q);

// free dynamic cast function
template<class X, class Y> CloneablePtr<X> DynamicCast(const CloneablePtr<Y>& p);


// Equality testing
template<class X, class Y>
bool operator==(const CloneablePtr<X>& a, const CloneablePtr<Y>& b);

template<class X, class Y>
bool operator!=(const CloneablePtr<X>& a, const CloneablePtr<Y>& b);

// MakeCloneable psuedo-variadic template
template<class T, class... Args>
CloneablePtr<T> MakeCloneable(Args&&... args);
// EXCEPTIONS: may throw an exception if constructor for T throws
// or memory allocation fails


// EXCEPTIONS: unless otherwise specified, the methods above
// never throw an exception (under C++11 rules, if a destructor
// is invoked that throws an exception, the program will terminate).






/**********************************************************************

UniquePtr<T> -- unique pointer to object with copying disabled.
Useful for pointers inside classes so that we can
automatically destruct them.  

Constructors:
   UniquePtr<T> p1;     // initialize with null
   UniquePtr<T> p1(0); 

   T* rp;
   UniquePtr<T> p1(rp); // construct using raw pointer (explicit)

   p1 = 0;              // destroy's p1's referent and assigns null

   p1.make(...);        // destroy's p1's referent and assigns
                        // a fresh objected constructed via T(...),
                        // using psuedo-variadic templates
                
   p1.reset(rp);        // destroy's p1's referent and assign rp

   if (!p1) ...         // test for null
   if (p1 == 0) ...

   if (p1) ...          // test for nonnull
   if (p1 != 0) ...

   if (p1 == p2) ...    // test for equality
   if (p1 != p2) ...   

   *p1                  // dereferencing
   p1->...


   rp = p1.get();       // fetch raw pointer
   rp = p1.release();   // fetch raw pointer, and set to null

   p1.move(p2);         // move p2 to p1, destroying p1's referent
                        //   if p1 != p2

   p1.swap(p2);         // swap pointers
   swap(p1, p2);


DeleterPolicy:

UniquePtr supports a "deleter policy", analogous to that used in SmartPtr.

Normally, when the object pointed to a UniquePtr needs to be destroyed, this is
done by invoking delete on the raw pointer.  The user can override this
behavior by specifying a "deleter policy", which is a class P that defines a
static member function deleter, which is invoked as P::deleter(p).  

Unlike with a SmartPtr, the deleter policy must be attached to the type.
The default policy is the same DefaultDeleterPolicy, defined above.

A deleter policy can be useful, for example, in realizing the PIPL
pattern, where the class T's definition is not visible.  The specified deleter
can invoke a free-standing function that itself invokes delete.  A deleter
policy can also be useful is memory is to be managed using some mechanism other
than new/delete.

   
**********************************************************************/


template<class T, class P=DefaultDeleterPolicy>
class UniquePtr {
public:
   explicit UniquePtr(T *p);
   // construct UniquePtr from raw pointer (allocated with new)

   UniquePtr();
   // initial value is null

   UniquePtr(UniquePtr&& other) noexcept;
   UniquePtr& operator=(UniquePtr&& other) noexcept;
   // move semantics (C++11 only)

   UniquePtr& operator=(fake_null_type1);
   // allows assignment of 0; equivalent to calling reset()

   ~UniquePtr();
   // destroys referent by calling P::deleter

   void reset(T* p = 0);
   // reset underlying pointer to p, destroying original referent
   // by calling P::deleter

   template<class T, class... Args>
   void make(Args&&... args);
   // pseudo-variadic template, roughly equivalent to
   // reset(new T(std::forward<args> args...))
   // EXCEPTIONS: this may throw (but provides strong ES guarantee)

   T& operator*()  const;
   T* operator->() const;
   // indirection

   T* get() const;
   // get raw pointer

   T* release();
   // returns raw pointer, and sets the raw pointer to null

   void move(UniquePtr& other);
   // move other to *this, destroying original referent
   // by calling P::deleter

   void swap(UniquePtr& other);
   // swap raw pointers

   operator fake_null_type() const;
   // allows comparison with 0

private:
   UniquePtr(const UniquePtr&); // disabled
   void operator=(const UniquePtr&); // disabled
};


// free swap function
template<class T> void swap(UniquePtr<T>& p, UniquePtr<T>& q);



// Equality testing

template<class X, class P> bool operator==(const UniquePtr<X,P>& a, const UniquePtr<X,P>& b);
template<class X, class P> bool operator!=(const UniquePtr<X,P>& a, const UniquePtr<X,P>& b);


// EXCEPTIONS: unless otherwise specified, the methods above
// never throw an exception (under C++11 rules, if a destructor
// is invoked that throws an exception, the program will terminate).


/**********************************************************************

CopiedPtr<T> -- essentially the same interface and implemetation as UniquePtr,
with the following exceptions:

 * copy constructor is defined: by default, it will create a copy
   of the referrent using T's copy constructor (but this bahavior
   can be overridden -- see below)

 * assignment operator is defined (and implemented in terms of the
   copy constructor)

 * The policy managing a CopiedPtr specifier deleter and copier functions:
   the deleter is used to delete objects and the copies is used for making
   copies (see below).

NOTE: this class is meant to replace the OptionalVal class, whose
interface is not so nice.  For backwards compatibility, OptionalVal will
be maintained, however.
   
**********************************************************************/


// This class specifies the default copier
struct DefaultCopierPolicy {

   template<class T>
   static T* copier(T *p) { return (p ?  MakeRaw<T>(*p) : 0); }

};

// This class specifies an alternative copier, which is meant
// to perform "deep" copies on class heirarchies that support an
// appropriate clone() method.
struct CloningCopier {

   template<class T>
   static T* copier(T *p) { return (p ?  p->clone() : 0); }

};

struct DefaultCopiedPtrPolicy : DefaultDeleterPolicy, DefaultCopierPolicy { };
struct CloningCopiedPtrPolicy : DefaultDeleterPolicy, CloningCopier { };



template<class T, class P=DefaultCopiedPtrPolicy>
class CopiedPtr {
public:
   explicit CopiedPtr(T *p);
   // construct CopiedPtr from raw pointer (allocated with new)

   CopiedPtr();
   // initial value is null

   CopiedPtr(const CopiedPtr& other);
   // creates a copy of other's referent by calling P::copier

   void operator=(const CopiedPtr&);
   // creates a copy of other's referent by calling P::copier,
   // and destroys original referent by calling P::deleter

   CopiedPtr& operator=(fake_null_type1);
   // allows assignment of 0; equivalent to calling reset()

   ~CopiedPtr();
   // destroys referent by calling P::deleter

   CopiedPtr(CopiedPtr&& other) noexcept;
   CopiedPtr& operator=(CopiedPtr&& other) noexcept;
   // move semantics (C++11 only)

   void reset(T* p = 0);
   // reset underlying pointer to p, destroying original referent
   // by calling P::deleter

   template<class T, class... Args>
   void make(Args&&... args);
   // pseudo-variadic template, roughly equivalent to
   // reset(new T(std::forward<args> args...))
   // EXCEPTIONS: this may throw (but provides strong ES guarantee)

   T& operator*()  const;
   T* operator->() const;
   // indirection

   T* get() const;
   // get raw pointer

   T* release();
   // returns raw pointer, and sets the raw pointer to null

   void move(CopiedPtr& other);
   // move other to *this, destroying original referent
   // by calling P::deleter


   void swap(CopiedPtr& other);
   // swap raw pointers

   operator fake_null_type() const;
   // allows comparison with 0

};


// free swap function
template<class T> void swap(CopiedPtr<T>& p, CopiedPtr<T>& q);



// Equality testing

template<class X, class P> bool operator==(const CopiedPtr<X,P>& a, const CopiedPtr<X,P>& b);
template<class X, class P> bool operator!=(const CopiedPtr<X,P>& a, const CopiedPtr<X,P>& b);


// EXCEPTIONS: unless otherwise specified, the methods above
// never throw an exception (under C++11 rules, if a destructor
// is invoked that throws an exception, the program will terminate).




/**********************************************************************

UniqueArray<T> -- similar to UniquePtr, but for arrays.  These arrays cannot be
resized -- for that, you should use the Vec class.

Constructors:
   UniqueArray<T> p1;     // initialize with null
   UniqueArray<T> p1(0); 

   T* rp;
   UniqueArray<T> p1(rp); // construct using raw pointer (explicit)

   p1 = 0;              // destroy's p1's referent and assigns null

   p1.SetLength(n);     // destroy's p1's referent and assigns
                        // a fresh objected constructed via new T[n]
                
   p1.reset(rp);        // destroy's p1's referent and assign rp

   if (!p1) ...         // test for null
   if (p1 == 0) ...

   if (p1) ...          // test for nonnull
   if (p1 != 0) ...

   if (p1 == p2) ...    // test for equality
   if (p1 != p2) ...   

   p1[i]                // array indexing

   rp = p1.get();       // fetch raw pointer
   rp = p1.release();   // fetch raw pointer, and set to null
   p1.move(p2);         // move p2 to p1, destroying p1's referent 
                        //   if p1 != p2

   p1.swap(p2);         // fast swap
   swap(p1, p2);

   
**********************************************************************/


template<class T>
class UniqueArray {
public:
   explicit UniqueArray(T *p);
   // construct from raw pointer (allocated with new[])

   UniqueArray();
   // initially null

   UniqueArray& operator=(fake_null_type1);
   // allows of 0

   ~UniqueArray();

   UniqueArray(UniqueArray&& other) noexcept;
   UniqueArray& operator=(UniqueArray&& other) noexcept;
   // move semantics (C++11 only)

   void reset(T* p = 0);
   // reset with raw pointer, destroying referent

   void SetLength(long n);
   // destroys referent and allocates an array of size n
   // EXCEPTIONS: this may throw (but provides strong ES guarantee)

   T& operator[](long i) const;
   // accesses ith element in the array (currently no range checking)

   T* get() const;
   // get raw pointer

   T* elts() const;
   // get raw pointer (for compatibility with the Vec class)

   T* release();
   // get raw pointer and reset to null

   void move(UniqueArray& other);
   // move raw pointer

   void swap(UniqueArray& other);
   // swap raw pointer

   operator fake_null_type() const;
   // allows comparison to 0

private:
   UniqueArray(const UniqueArray&); // disabled
   void operator=(const UniqueArray&); // disabled

};



// free swap function
template<class T> void swap(UniqueArray<T>& p, UniqueArray<T>& q);



// Equality testing

template<class X> bool operator==(const UniqueArray<X>& a, const UniqueArray<X>& b);
template<class X> bool operator!=(const UniqueArray<X>& a, const UniqueArray<X>& b);




/**********************************************************************

Unique2DArray<T> -- unique pointer to array of arrays.

This is very similar to UniqueArray< UniqueArray<T> >, except that 
we can retrofit old code that accepts objects of type T**.

Constructors:
   Unique2DArray<T> p1;     // initialize with null
   Unique2DArray<T> p1(0); 

   p1 = 0;              // destroy's p1's referent and assigns null
   p1.reset();

   p1.SetLength(n);     // destroy's p1's referent and assigns
                        // a fresh array of null pointers

   p1.SetDims(n, m)     // creates an n x m array
                
   if (!p1) ...         // test for null
   if (p1 == 0) ...

   if (p1) ...          // test for nonnull
   if (p1 != 0) ...

   if (p1 == p2) ...    // test for equality
   if (p1 != p2) ...   

   p1[i]                // array indexing

   T **rp;
   rp = p1.get();       // fetch raw pointer
   rp = p1.release();   // fetch raw pointer, and set to null
   p1.move(p2);         // if p1 != p2 then:
                        //    makes p1 point to p2's referent,
                        //    setting p2 to null and destroying
                        //    p1's referent

   p1.swap(p2);         // fast swap
   swap(p1, p2);

   
**********************************************************************/


template<class T>
class Unique2DArray {
public:
   typedef T *T_ptr;

   Unique2DArray();
   // initially null

   Unique2DArray& operator=(fake_null_type1);
   // allows initialization and assignment of 0

   ~Unique2DArray();
   // destroys the entire array and each row in the array

   Unique2DArray(Unique2DArray&& other) noexcept;
   Unique2DArray& operator=(Unique2DArray&& other) noexcept;
   // move semantics (C++11 only)

   void reset();
   // reset to null


   void SetLength(long n);
   // resets the array to a vector of length n,
   // each entry initialized to null.
   // EXCEPTIONS: may throw (provides strong ES guarantee)

   void SetDims(long n, long m);
   // resets the array to a 2D array with n rows and m columns.
   // EXCEPTIONS: may throw (provides strong ES guarantee)

   void SetDimsFrom1(long n, long m);
   // same as above, but only initializes rows 1..n-1.
   // this helps with some legacy code.
   // EXCEPTIONS: may throw (provides strong ES guarantee)

   T_ptr& operator[](long i) const;
   // array indexing, no range checking

   T_ptr* get() const;
   // return underlying pointer

   T_ptr* release() { len = 0; return dp.release(); }
   // return underlying pointer and reset to null


   void move(Unique2DArray& other);
   // move pointers

   void swap(Unique2DArray& other);
   // swap pointers

   operator fake_null_type() const;
   // allows comparison to 0


private:

   Unique2DArray(const Unique2DArray&); // disabled
   void operator=(const Unique2DArray&); // disabled

};


// free swap function
template<class T> void swap(Unique2DArray<T>& p, Unique2DArray<T>& q);



// Equality testing

template<class X> bool operator==(const Unique2DArray<X>& a, const Unique2DArray<X>& b);
template<class X> bool operator!=(const Unique2DArray<X>& a, const Unique2DArray<X>& b);





/**********************************************************************


OptionalVal<T> -- unique pointer to object with copying enabled.

NOTE: this class is deprecated; use CopiedPtr instead.
It will, however, be maintained indefinitely for backward compatibility.

Constructors:
   OptionalVal<T> p1;     // initialize with null

   T* rp;
   OptionalVal<T> p1(rp); // construct using raw pointer (explicit)

   OptionalVal<T> p2(p1); // construct a copy of p1's referent

    

   p1.make(...);        // destroy's p1's referent and assigns
                        // a fresh objected constructed via T(...),
                        // using psuedo variadic templates
                
   p1.reset(rp);        // destroy's p1's referent and assign rp

   if (p1.exists()) ... // test for null

   p1.val()             // dereference

   rp = p1.get();       // fetch raw pointer
   rp = p1.release();   // fetch raw pointer, and set to NULL
   p1.move(p2);         // move p2 to p1, destroying p1's referent
                        //   if p1 != p2

   p1 = p2;             // deep copy, using T's copy constructor

   p1.swap(p2);         // swap pointers
   swap(p1, p2);

   
**********************************************************************/


template<class T>
class OptionalVal {
public:
   explicit OptionalVal(T *p);
   // initialize using raw pointer (allocated with new)

   OptionalVal();
   // initialize to null

   OptionalVal(const OptionalVal& other);
   // initialize using a deep copy (via T's copy constructor)

   OptionalVal& operator=(const OptionalVal& other);
   // assignment using a deep copy (via T's copy constructor)

   ~OptionalVal();
   // destroys the referent

   OptionalVal(OptionalVal&& other) noexcept;
   OptionalVal& operator=(OptionalVal&& other) noexcept;
   // move semantics (C++11 only)

   void reset(T* p = 0);
   // resets the referent

   template<class T, class... Args>
   void make(Args&&... args);
   // pseudo-variadic template.
   // resets the referent to a new object T(std::forward<Args> args...)
   // EXCEPTIONS: may throw an exception (but provides strong ES guarantee)

   T& val() const;
   // returns reference to referent 
   // if underlying pointer p is null, the indirection *p
   // is undefined behavior, but most likely leads to program termination

   bool exists() const;
   // checks that underlying pointer is not null

   T* get() const;
   // returns underlying raw pointer

   T* release();
   // returns raw pointer, and sets the raw pointer to null

   void move(OptionalVal& other);
   // performs a (shallow) pointer move

   void swap(OptionalVal& other);
   // performs a (shallow) pointer swap

};


// free swap function
template<class T> void swap(OptionalVal<T>& p, OptionalVal<T>& q);



// EXCEPTIONS: unless otherwise specified, the methods above
// never throw an exception (under C++11 rules, if a destructor
// is invoked that throws an exception, the program will terminate).

ntl-11.5.1/doc/ZZ.cpp.html0000644417616742025610000021715214064716023016745 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ.cpp.html

/**************************************************************************\

MODULE: ZZ

SUMMARY:

The class ZZ is used to represent signed, arbitrary length integers.

Routines are provided for all of the basic arithmetic operations, as
well as for some more advanced operations such as primality testing.
Space is automatically managed by the constructors and destructors.

This module also provides routines for generating small primes, and
fast routines for performing modular arithmetic on single-precision
numbers.


\**************************************************************************/

#include <NTL/tools.h>


class ZZ {
public:


   ZZ(); // initial value is 0

   ZZ(const ZZ& a);  // copy constructor
   explicit ZZ(long a);  // promotion constructor

   ~ZZ(); // destructor

   ZZ& operator=(const ZZ& a);  // assignment operator
   ZZ& operator=(long a);

   ZZ(ZZ&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

   ZZ& operator=(ZZ&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set



   // typedefs to aid in generic programming
   typedef ZZ_p residue_type;
   typedef ZZX poly_type;


   // ...

};


// NOTE: A ZZ is represented as a sequence of "limbs",
// where each limb is between 0 and 2^{NTL_ZZ_NBITS-1}.

// NTL_ZZ_NBITS is  macros defined in <NTL/ZZ.h>.

// SIZE INVARIANT: the number of bits in a ZZ is always less than
// 2^(NTL_BITS_PER_LONG-4).



/**************************************************************************\

                                 Comparison

\**************************************************************************/



// The usual comparison operators: 

long operator==(const ZZ& a, const ZZ& b);
long operator!=(const ZZ& a, const ZZ& b);
long operator<(const ZZ& a, const ZZ& b);
long operator>(const ZZ& a, const ZZ& b);
long operator<=(const ZZ& a, const ZZ& b);
long operator>=(const ZZ& a, const ZZ& b);

// other stuff:

long sign(const ZZ& a); // returns sign of a (-1, 0, +1)
long IsZero(const ZZ& a); // test for 0
long IsOne(const ZZ& a); // test for 1

long compare(const ZZ& a, const ZZ& b); // returns sign of a-b (-1, 0, or 1).

// PROMOTIONS: the comparison operators and the function compare
// support promotion from long to ZZ on (a, b).


/**************************************************************************\

                                 Addition

\**************************************************************************/


// operator notation:

ZZ operator+(const ZZ& a, const ZZ& b);
ZZ operator-(const ZZ& a, const ZZ& b);
ZZ operator-(const ZZ& a); // unary -

ZZ& operator+=(ZZ& x, const ZZ& a);
ZZ& operator+=(ZZ& x, long a);

ZZ& operator-=(ZZ& x, const ZZ& a);
ZZ& operator-=(ZZ& x, long a);

ZZ& operator++(ZZ& x);  // prefix
void operator++(ZZ& x, int);  // postfix

ZZ& operator--(ZZ& x);  // prefix
void operator--(ZZ& x, int);  // postfix



// procedural versions:

void add(ZZ& x, const ZZ& a, const ZZ& b); // x = a + b
void sub(ZZ& x, const ZZ& a, const ZZ& b); // x = a - b
void SubPos(ZZ& x, const ZZ& a, const ZZ& b); // x = a-b; assumes a >= b >= 0.
void negate(ZZ& x, const ZZ& a); // x = -a

void abs(ZZ& x, const ZZ& a); // x = |a|
ZZ abs(const ZZ& a);

// PROMOTIONS: binary +, -, as well as the procedural versions add, sub
// support promotions from long to ZZ on (a, b).


/**************************************************************************\

                             Multiplication

\**************************************************************************/

// operator notation:

ZZ operator*(const ZZ& a, const ZZ& b);

ZZ& operator*=(ZZ& x, const ZZ& a);
ZZ& operator*=(ZZ& x, long a);

// procedural versions:

void mul(ZZ& x, const ZZ& a, const ZZ& b); // x = a * b

void sqr(ZZ& x, const ZZ& a); // x = a*a
ZZ sqr(const ZZ& a);

// PROMOTIONS: operator * and procedure mul support promotion
// from long to ZZ on (a, b).

/**************************************************************************\

                            Combined Multiply and Add 

\**************************************************************************/


void MulAddTo(ZZ& x, const ZZ& a, const ZZ& b); // x += a*b
void MulAddTo(ZZ& x, const ZZ& a, long b);      // x += a*b


void MulSubFrom(ZZ& x, const ZZ& a, const ZZ& b); // x -= a*b
void MulSubFrom(ZZ& x, const ZZ& a, long b);      // x -= a*b

// NOTE: these are provided for both convenience and efficiency.
// The single-precision versions may be significantly
// faster than the code sequence 
//   mul(tmp, a, b); add(x, x, tmp);
// However, for the single-precision version, the use-case
// that is optimized is for |b| < 2^{NTL_WSP_BOUND}.



/**************************************************************************\

                                 Division

\**************************************************************************/


// operator notation:

ZZ operator/(const ZZ& a, const ZZ& b);
ZZ operator/(const ZZ& a, long  b);

ZZ operator%(const ZZ& a, const ZZ& b);
long operator%(const ZZ& a, long b);

ZZ& operator/=(ZZ& x, const ZZ& b);
ZZ& operator/=(ZZ& x, long b);

ZZ& operator%=(ZZ& x, const ZZ& b);


// procedural versions:

void DivRem(ZZ& q, ZZ& r, const ZZ& a, const ZZ& b);
// q = floor(a/b), r = a - b*q.
// This implies that:
//    |r| < |b|, and if r != 0, sign(r) = sign(b)

void div(ZZ& q, const ZZ& a, const ZZ& b);
// q = floor(a/b)

void rem(ZZ& r, const ZZ& a, const ZZ& b);
// q = floor(a/b), r = a - b*q


// single-precision variants:

long DivRem(ZZ& q, const ZZ& a, long b);
// q = floor(a/b), r = a - b*q, return value is r.

long rem(const ZZ& a, long b);
// q = floor(a/b), r = a - b*q, return value is r.


// divisibility testing:

long divide(ZZ& q, const ZZ& a, const ZZ& b);
long divide(ZZ& q, const ZZ& a, long b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0.

long divide(const ZZ& a, const ZZ& b);
long divide(const ZZ& a, long b);
// if b | a, returns 1; otherwise returns 0.


/**************************************************************************\

                                    GCD's

\**************************************************************************/


void GCD(ZZ& d, const ZZ& a, const ZZ& b);
ZZ GCD(const ZZ& a, const ZZ& b);

// d = gcd(a, b) (which is always non-negative).  Uses a binary GCD
// algorithm.



void XGCD(ZZ& d, ZZ& s, ZZ& t, const ZZ& a, const ZZ& b);

//  d = gcd(a, b) = a*s + b*t.

// The coefficients s and t are defined according to the standard
// Euclidean algorithm applied to |a| and |b|, with the signs then
// adjusted according to the signs of a and b.

// The implementation may or may not Euclid's algorithm,
// but the coefficients s and t are always computed as if 
// it did.

// In particular, the following inequalties should hold:
//    |s| <= 1   OR   |s| < |b|/(2*d)
//    |t| <= 1   OR   |t| < |a|/(2*d)



// special-purpose single-precision variants:

long GCD(long a, long b);
// return value is gcd(a, b) (which is always non-negative)

void XGCD(long& d, long& s, long& t, long a, long b);
//  d = gcd(a, b) = a*s + b*t.

//  The coefficients s and t are defined according to the standard
//  Euclidean algorithm applied to |a| and |b|, with the signs then
//  adjusted according to the signs of a and b.



/**************************************************************************\

                             Modular Arithmetic

The following routines perform arithmetic mod n, where n > 1.

All arguments (other than exponents) are assumed to be in the range
0..n-1.  Some routines may check this and raise an error if this
does not hold.  Others may not, and the behaviour is unpredictable
in this case.

\**************************************************************************/



void AddMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a+b)%n
ZZ AddMod(const ZZ& a, const ZZ& b, const ZZ& n);

void SubMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a-b)%n
ZZ SubMod(const ZZ& a, const ZZ& b, const ZZ& n);

void NegateMod(ZZ& x, const ZZ& a, const ZZ& n); // x = -a % n
ZZ NegateMod(const ZZ& a, const ZZ& n);

void MulMod(ZZ& x, const ZZ& a, const ZZ& b, const ZZ& n); // x = (a*b)%n
ZZ MulMod(const ZZ& a, const ZZ& b, const ZZ& n);

void SqrMod(ZZ& x, const ZZ& a, const ZZ& n); // x = a^2 % n
ZZ SqrMod(const ZZ& a, const ZZ& n);




void InvMod(ZZ& x, const ZZ& a, const ZZ& n);
ZZ InvMod(const ZZ& a, const ZZ& n);
// x = a^{-1} mod n (0 <= x < n); error is raised occurs if inverse
// not defined

// If exceptions are enabled, an object of the following class 
// is throw by the InvMod routine if the inverse of a mod n is
// not defined. The methods get_a() and get_n() give read-only
// access to the offending values of a and n.
// This also happens for any indirect call to InvMod, via PowerMod,
// of via inverse computations in ZZ_p.

class InvModErrorObject : public ArithmeticErrorObject {
public:
   InvModErrorObject(const char *s, const ZZ& a, const ZZ& n);
   const ZZ& get_a() const;
   const ZZ& get_n() const;
};

long InvModStatus(ZZ& x, const ZZ& a, const ZZ& n);
// if gcd(a,n) = 1, then return-value = 0, x = a^{-1} mod n;
// otherwise, return-value = 1, x = gcd(a, n)

void PowerMod(ZZ& x, const ZZ& a, const ZZ& e, const ZZ& n);
ZZ PowerMod(const ZZ& a, const ZZ& e, const ZZ& n);

void PowerMod(ZZ& x, const ZZ& a, long e, const ZZ& n);
ZZ PowerMod(const ZZ& a, long e, const ZZ& n);

// x = a^e % n (e may be negative)


// PROMOTIONS: AddMod, SubMod, and MulMod (both procedural and functional
// forms) support promotions from long to ZZ on (a, b).






/**************************************************************************\

                        Single-precision modular arithmetic

These routines implement single-precision modular arithmetic.  If n is
the modulus, all inputs should be in the range 0..n-1.  The number n
itself should be in the range 2..NTL_SP_BOUND-1.

Most of these routines are, of course, implemented as fast inline
functions.  No checking is done that inputs are in range.


\**************************************************************************/




long AddMod(long a, long b, long n); // return (a+b)%n

long SubMod(long a, long b, long n); // return (a-b)%n

long NegateMod(long a, long n); // return (-a)%n

long MulMod(long a, long b, long n); // return (a*b)%n

long MulMod(long a, long b, long n, mulmod_t ninv);
// return (a*b)%n.  
//
// Usually faster than plain MulMod when n is fixed for many
// invocations. The value ninv should be precomputed as 
//   mulmod_t ninv = PrepMulMod(n);

mulmod_t PrepMulMod(long n);
// Prepare auxiliary data for MulMod.

long MulModPrecon(long a, long b, long n, mulmod_precon_t bninv);
// return (a*b)%n.  
//
// Usually much faster than MulMod when both b and n are fixed for 
// many invocations.  The value bninv should be precomputed as
//   mulmod_precon_t bninv = PrepMulModPrecon(b, n);
// or as
//   mulmod_precon_t bninv = PrepMulModPrecon(b, n, ninv);
// where ninv = PrepMulMod(n).

mulmod_precon_t PrepMulModPrecon(long b, long n);
mulmod_precon_t PrepMulModPrecon(long b, long n, mulmod_t ninv);
// Prepare auxiliary data for MulModPrecon.
// In the second version, ninv = PrepMulMod(n).



long InvMod(long a, long n);
// computes a^{-1} mod n.  Error is raised if undefined.

long InvModStatus(long& x, long a, long n);
// if gcd(a,n) = 1, then return-value = 0, x = a^{-1} mod n;
// otherwise, return-value = 1, x = gcd(a, n)

long PowerMod(long a, long e, long n);
// computes a^e mod n (e may be negative)

// The following are vector versions of the MulMod routines
// They each compute x[i] = (a[i] * b)% n   i = 0..k-1 

void VectorMulMod(long k, long *x, const long *a, long b, long n);

void VectorMulMod(long k, long *x, const long *a, long b, long n,
                  mulmod_t ninv);
// ninv = PrepMulMod(n)

void VectorMulModPrecon(long k, long *x, const long *a, long b, long n,
                        mulmod_precon_t bninv);
// bninv = MulModPrecon(b, n)


// The following is provided for legacy support, but is not generally 
// recommended:

long MulDivRem(long& q, long a, long b, long n, muldivrem_t bninv);
// return (a*b)%n, set q = (a*b)/n.  
// The value bninv should be precomputed as 
//   muldivrem_t bninv = PrepMulDivRem(b, n);
// or as
//   muldivrem_t bninv = PrepMulDivRem(b, n, ninv);
// where ninv = PrepMod(n).

 muldivrem_t PrepMulDivRem(long b, long n);
 muldivrem_t PrepMulDivRem(long b, long n, mulmod_t ninv);
// Prepare auxiliary data for MulDivRem.
// In the second version, ninv = PrepMulMod(n).

// NOTE: despite the similarity in the interface to MulModPrecon,
// this routine is typically implemented in a very different way,
// and usually much less efficient.
// It was initially designed for specialized, internal use
// within NTL, but has been a part of the documented NTL
// interface for some time, and remains so even after the
// v9.0 upgrade.



//
// Compatibility notes:
//
// The types mulmod_t and muldivrem_t were introduced in NTL v9.0, as were the
// functions PrepMulMod and PrepMulDivRem.  Prior to this, the built-in type
// "double" played the role of these types, and the user was expected to
// compute PrepMulMod(n) as 1/double(n) and PrepMulDivRem(b, n) as
// double(b)/double(n).
// 
// By abstracting these types, NTL is able to exploit a wider variety of
// implementation strategies.  Some old client code may break, but the compiler
// will easily find the code that needs to be updated, and the updates are
// quite mechanical (unless the old code implicitly made use of the assumption
// that NTL_SP_NBITS <= NTL_DOUBLE_PRECISION-3).
//
// It is highly recommended that old client codes be updated.  However, one may
// build NTL with the configuration option NTL_LEGACY_SP_MULMOD=on, which will
// cause the interfaces and implementations to revert to their pre-v9.0
// definitions.  This option will also make the following (obsolete) function
// visible:

    long MulMod2(long a, long b, long n, double bninv);
    // return (a*b)%n.  bninv = ((double) b)/((double) n).  This is faster
    // if both n and b are fixed for many multiplications.
    // Note: This is OBSOLETE -- use MulModPrecon.


// As of v9.2 of NTL, this new interface allows for 60-bit moduli on most
// 64-bit machines.  The requirement is that a working 128-bit integer type is
// available.  For current versions of gcc, clang, and icc, this is available
// vie the types __int128_t and __uint128_t.  If this requirement is met (which
// is verified during NTL installation), then a "long long" implementation for
// MulMod is used.  In versions 9.0 and 9.1 of NTL, a "long double"
// implementation was introduced, which utilized the 80-bit extended double
// precision hardware on x86 machines.  This also allows for 60-bit moduli on
// 64-bit machines.

// If 128-bit integer types are not available, or if you build NTL with the
// NTL_DISABLE_LONGLONG=on flag, NTL will attempt to use the extended double
// precision hardware to still allow 60-bit moduli.  If that is not possible,
// or if you build NTL with the NTL_DISABLE_LONGDOUBLE=on flag, then NTL will
// fall back to its "classical" implementation (pre-9.0) that relies on
// double-precision arithmetic and imposes a 50-bit limit on moduli.  

// Note that in on 64-bit machines, either the "long long" or "long double"
// implementations could support 62-bit moduli, rather than 60-bit moduli.
// However, the restriction to 60-bits speeds up a few things, and so seems
// like a good trade off.  This is subject to change in the future.

// Also note that all of these enhancements introduced since v9.0 are only
// available to builds of NTL that use GMP.  Builds that don't use GMP will
// still be restricted to 50-bit moduli on 64-bit machines. 

// On machines with 32-bit longs, moduli will be resricted to 30 bits,
// regardless on the implementation, which will be based on "long long"
// arithmetic (if a 64-bit integer type is available), or on double-precision
// floating point (otherwise).

// One can detect the new (v9) interface by testing if the macro
// NTL_HAVE_MULMOD_T is defined.  The following code can be used to make
// new-style NTL clients work with either older (pre-9.0) versions of NTL or
// newer versions (post-9.0):


   #ifndef NTL_HAVE_MULMOD_T
      namespace NTL {
         typedef double mulmod_t;
         typedef double muldivrem_t;

         static inline double PrepMulMod(long n)
         { return double(1L)/double(n); }

         static inline double PrepMulDivRem(long b, long n, double ninv)
         { return double(b)*ninv; }

         static inline double PrepMulDivRem(long b, long n)
         { return double(b)/double(n); }

         static inline double PrepMulModPrecon(long b, long n)
         { return PrepMulModPrecon(b, n, PrepMulMod(n)); }
      }
   #endif





/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by 2^n
RightShift by n means division by 2^n, with truncation toward zero
  (so the sign is preserved).

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ operator<<(const ZZ& a, long n);
ZZ operator>>(const ZZ& a, long n);

ZZ& operator<<=(ZZ& x, long n);
ZZ& operator>>=(ZZ& x, long n);

// procedural versions:

void LeftShift(ZZ& x, const ZZ& a, long n);
ZZ LeftShift(const ZZ& a, long n);

void RightShift(ZZ& x, const ZZ& a, long n);
ZZ RightShift(const ZZ& a, long n);



/**************************************************************************\

                              Bits and Bytes

\**************************************************************************/



long MakeOdd(ZZ& x);
// removes factors of 2 from x, returns the number of 2's removed
// returns 0 if x == 0

long NumTwos(const ZZ& x);
// returns max e such that 2^e divides x if x != 0, and returns 0 if x == 0.

long IsOdd(const ZZ& a); // test if a is odd

long NumBits(const ZZ& a);
long NumBits(long a);
// returns the number of bits in binary represenation of |a|; 
// NumBits(0) = 0


long bit(const ZZ& a, long k);
long bit(long a, long k);
// returns bit k of |a|, position 0 being the low-order bit.
// If  k < 0 or k >= NumBits(a), returns 0.


void trunc(ZZ& x, const ZZ& a, long k);
// x = low order k bits of |a|. 
// If k <= 0, x = 0.

// two functional variants:
ZZ trunc_ZZ(const ZZ& a, long k);
long trunc_long(const ZZ& a, long k);

long SetBit(ZZ& x, long p);
// returns original value of p-th bit of |a|, and replaces p-th bit of
// a by 1 if it was zero; low order bit is bit 0; error if p < 0;
// the sign of x is maintained

long SwitchBit(ZZ& x, long p);
// returns original value of p-th bit of |a|, and switches the value
// of p-th bit of a; low order bit is bit 0; error if p < 0
// the sign of x is maintained

long weight(const ZZ& a); // returns Hamming weight of |a|
long weight(long a);

// bit-wise Boolean operations, procedural form:

void bit_and(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| AND |b|
void bit_or(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| OR |b|
void bit_xor(ZZ& x, const ZZ& a, const ZZ& b); // x = |a| XOR |b|

// bit-wise Boolean operations, operator notation:

ZZ operator&(const ZZ& a, const ZZ& b);
ZZ operator|(const ZZ& a, const ZZ& b);
ZZ operator^(const ZZ& a, const ZZ& b);

// PROMOTIONS: the above bit-wise operations (both procedural 
// and operator forms) provide promotions from long to ZZ on (a, b).

ZZ& operator&=(ZZ& x, const ZZ& b);
ZZ& operator&=(ZZ& x, long b);

ZZ& operator|=(ZZ& x, const ZZ& b);
ZZ& operator|=(ZZ& x, long b);

ZZ& operator^=(ZZ& x, const ZZ& b);
ZZ& operator^=(ZZ& x, long b);



// conversions between byte sequences and ZZ's

void ZZFromBytes(ZZ& x, const unsigned char *p, long n);
ZZ ZZFromBytes(const unsigned char *p, long n);
// x = sum(p[i]*256^i, i=0..n-1). 
// NOTE: in the unusual event that a char is more than 8 bits, 
//       only the low order 8 bits of p[i] are used

void BytesFromZZ(unsigned char *p, const ZZ& a, long n);
// Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n.

long NumBytes(const ZZ& a);
long NumBytes(long a);
// returns # of base 256 digits needed to represent abs(a).
// NumBytes(0) == 0.




/**************************************************************************\

                            Pseudo-Random Numbers

\**************************************************************************/


// Routines for generating pseudo-random numbers.

// These routines generate high qualtity, cryptographically strong
// pseudo-random numbers.  They are implemented so that their behaviour
// is completely independent of the underlying hardware and long 
// integer implementation.  Note, however, that other routines 
// throughout NTL use pseudo-random numbers, and because of this,
// the word size of the machine can impact the sequence of numbers
// seen by a client program.


void SetSeed(const ZZ& s);
void SetSeed(const unsigned char *data, long dlen);
void SetSeed(const RandomStream& s);
// Initializes generator with a "seed".

// The first version hashes the binary representation of s to obtain a key for
// a low-level RandomStream object (see below).

// The second version does the same, hashing the first dlen bytes pointed to by
// data to obtain a key for the RandomStream object.

// The third version initializes the PRG state directly with the given
// RandomStream object.

// EXCEPTIONS: strong ES


void RandomBnd(ZZ& x, const ZZ& n);
ZZ RandomBnd(const ZZ& n);
void RandomBnd(long& x, long n);
long RandomBnd(long n);
// x = pseudo-random number in the range 0..n-1, or 0 if n <= 0
// EXCEPTIONS: strong ES

void VectorRandomBnd(long k, long *x, long n);
// equivalent to x[i] = RandomBnd(n) for i in [0..k), but faster
// EXCEPTIONS: strong ES

void VectorRandomWord(long k, long *x);
// equivalent to x[i] = RandomWord(n) for i in [0..k), but faster
// EXCEPTIONS: strong ES


void RandomBits(ZZ& x, long l);
ZZ RandomBits_ZZ(long l);
void RandomBits(long& x, long l);
long RandomBits_long(long l);
// x = pseudo-random number in the range 0..2^l-1.
// EXCEPTIONS: strong ES

void RandomLen(ZZ& x, long l);
ZZ RandomLen_ZZ(long l);
void RandomLen(long& x, long l);
long RandomLen_long(long l);
// x = psuedo-random number with precisely l bits,
// or 0 of l <= 0.
// EXCEPTIONS: strong ES

unsigned long RandomBits_ulong(long l);
// returns a pseudo-random number in the range 0..2^l-1
// EXCEPTIONS: strong ES

unsigned long RandomWord();
// returns a word filled with pseudo-random bits.
// Equivalent to RandomBits_ulong(NTL_BITS_PER_LONG).
// EXCEPTIONS: strong ES



class RandomStream {
// The low-level pseudo-random generator (PRG).
// After initializing it with a key, one can effectively read an unbounded
// stream of pseudorandom bytes

public:

   explicit RandomStream(const unsigned char *key);
   // key should point to an array of NTL_PRG_KEYLEN bytes
   // EXCEPTIONS: strong ES

   void get(unsigned char *res, long n);
   // read the next n bytes from the stream and store to location pointed to by
   // res
   // EXCEPTIONS: throws a LogicError exception if n is negative

   RandomStream(const RandomStream&);
   // EXCEPTIONS: strong ES

   RandomStream& operator=(const RandomStream&);
   // EXCEPTIONS: strong ES
};


RandomStream& GetCurrentRandomStream();
// get reference to the current PRG state. If SetSeed has not been called, it
// is called with a default value (which should be unique to each
// process/thread).  NOTE: this is a reference to a thread-local object, so
// different threads will use different PRG's, and by default, each will be
// initialized with a unique seed.
// NOTE: using this reference, you can copy the current PRG state or assign a
// different value to it; however, see the helper class RandomStreamPush below,
// which may be more convenient.
// EXCEPTIONS: strong ES



class RandomStreamPush {
// RAII for saving/restoring current PRG state
public:
   RandomStreamPush();   // save a copy of the current PRG state
                         // EXCEPTIONS: strong ES

   ~RandomStreamPush();  // restore the saved copy of the PRG state

private:
   RandomStreamPush(const RandomStreamPush&); // disable
   void operator=(const RandomStreamPush&); // disable
};


void DeriveKey(unsigned char *key, long klen,
               const unsigned char *data, long dlen);
// utility routine to derive from the byte string (data, dlen) a byte string
// (key, klen).  Heuristically, if (data, dlen) has high entropy, then (key,
// klen) should be pseudorandom.  This routine is also used internally to
// derive PRG keys.
// EXCEPTIONS: throws LogicError exception if klen < 0 or hlen < 0



/**************************************************************************\

             Incremental Chinese Remaindering

\**************************************************************************/

long CRT(ZZ& a, ZZ& p, const ZZ& A, const ZZ& P);
long CRT(ZZ& a, ZZ& p, long A, long P);

// 0 <= A < P, (p, P) = 1; computes a' such that a' = a mod p, 
// a' = A mod P, and -p*P/2 < a' <= p*P/2; sets a := a', p := p*P, and
// returns 1 if a's value has changed, otherwise 0


/**************************************************************************\

                  Rational Reconstruction

\**************************************************************************/

long ReconstructRational(ZZ& a, ZZ& b, const ZZ& x, const ZZ& m,
                         const ZZ& a_bound, const ZZ& b_bound);

// 0 <= x < m, m > 2 * a_bound * b_bound,
// a_bound >= 0, b_bound > 0

// This routine either returns 0, leaving a and b unchanged, 
// or returns 1 and sets a and b so that
//   (1) a = b x (mod m),
//   (2) |a| <= a_bound, 0 < b <= b_bound, and
//   (3) gcd(m, b) = gcd(a, b).

// If there exist a, b satisfying (1), (2), and 
//   (3') gcd(m, b) = 1,
// then a, b are uniquely determined if we impose the additional
// condition that gcd(a, b) = 1;  moreover, if such a, b exist,
// then these values are returned by the routine.

// Unless the calling routine can *a priori* guarantee the existence
// of a, b satisfying (1), (2), and (3'),
// then to ensure correctness, the calling routine should check
// that gcd(m, b) = 1, or equivalently, gcd(a, b) = 1.

// This is implemented using a variant of Lehmer's extended
// Euclidean algorithm.

// Literature:  see G. Collins and M. Encarnacion, J. Symb. Comp. 20:287-297, 
// 1995; P. Wang, M. Guy, and J. Davenport, SIGSAM Bulletin 16:2-3, 1982. 


/**************************************************************************\

                                Primality Testing 
                           and Prime Number Generation

\**************************************************************************/

void GenPrime(ZZ& n, long l, long err = 80);
ZZ GenPrime_ZZ(long l, long err = 80);
long GenPrime_long(long l, long err = 80);

// GenPrime generates a random prime n of length l so that the
// probability that the resulting n is composite is bounded by 2^(-err).
// This calls the routine RandomPrime below, and uses results of 
// Damgard, Landrock, Pomerance to "optimize" 
// the number of Miller-Rabin trials at the end.

// Note that the prime generated by GenPrime and RandomPrime 
// is not entirely platform independent.  The behavior of the
// algorithm can depend on the size parameters, such as  NTL_SP_NBITS 
// NTL_ZZ_NBITS, and NTL_BITS_PER_LONG. However, on a given platform
// you will always get the same prime if you run the algorithm
// with the same RandomStream. 

// Note that RandomPrime and GenPrime are thread boosted.
// Nevertheless, their behavior is independent of the number of
// available threads and any indeterminacy arising from 
// concurrent computation.

void GenGermainPrime(ZZ& n, long l, long err = 80);
ZZ GenGermainPrime_ZZ(long l, long err = 80);
long GenGermainPrime_long(long l, long err = 80);

// A (Sophie) Germain prime is a prime p such that p' = 2*p+1 is also a prime.
// Such primes are useful for cryptographic applications...cryptographers
// sometimes call p' a "strong" or "safe" prime.
// GenGermainPrime generates a random Germain prime n of length l
// so that the probability that either n or 2*n+1 is not a prime
// is bounded by 2^(-err).

// Note that GenGermainPrime is thread boosted.
// Nevertheless, its behavior is independent of the number of
// available threads and any indeterminacy arising from 
// concurrent computation.

long ProbPrime(const ZZ& n, long NumTrials = 10);
long ProbPrime(long n, long NumTrials = 10);
// performs trial division, followed by one Miller-Rabin test
// to the base 2, followed by NumTrials Miller-witness tests 
// with random bases.

void RandomPrime(ZZ& n, long l, long NumTrials=10);
ZZ RandomPrime_ZZ(long l, long NumTrials=10);
long RandomPrime_long(long l, long NumTrials=10);
// n = random l-bit prime.  Uses ProbPrime with NumTrials.

void NextPrime(ZZ& n, const ZZ& m, long NumTrials=10);
ZZ NextPrime(const ZZ& m, long NumTrials=10);
// n = smallest prime >= m.  Uses ProbPrime with NumTrials.

long NextPrime(long m, long NumTrials=10);
// Single precision version of the above.
// Result will always be bounded by NTL_ZZ_SP_BOUND, and an
// error is raised if this cannot be satisfied.

long MillerWitness(const ZZ& n, const ZZ& w);
// Tests if w is a witness to compositeness a la Miller.  Assumption: n is
// odd and positive, 0 <= w < n.
// Return value of 1 implies n is composite.
// Return value of 0 indicates n might be prime.


/**************************************************************************\

                               Exponentiation

\**************************************************************************/


void power(ZZ& x, const ZZ& a, long e); // x = a^e (e >= 0)
ZZ power(const ZZ& a, long e);

void power(ZZ& x, long a, long e);

// two functional variants:
ZZ power_ZZ(long a, long e);
long power_long(long a, long e);

void power2(ZZ& x, long e); // x = 2^e (e >= 0)
ZZ power2_ZZ(long e);


/**************************************************************************\

                               Square Roots

\**************************************************************************/


void SqrRoot(ZZ& x, const ZZ& a); // x = floor(a^{1/2}) (a >= 0)
ZZ SqrRoot(const ZZ& a);

long SqrRoot(long a);




/**************************************************************************\

                    Jacobi symbol and modular square roots

\**************************************************************************/


long Jacobi(const ZZ& a, const ZZ& n);
//  compute Jacobi symbol of a and n; assumes 0 <= a < n, n odd

void SqrRootMod(ZZ& x, const ZZ& a, const ZZ& n);
ZZ SqrRootMod(const ZZ& a, const ZZ& n);
//  computes square root of a mod n; assumes n is an odd prime, and
//  that a is a square mod n, with 0 <= a < n.




/**************************************************************************\

                             Input/Output

I/O Format:

Numbers are written in base 10, with an optional minus sign.

\**************************************************************************/

istream& operator>>(istream& s, ZZ& x);
ostream& operator<<(ostream& s, const ZZ& a);



/**************************************************************************\

                            Miscellany

\**************************************************************************/


// The following macros are defined:

#define NTL_ZZ_NBITS (...)  // number of bits in a limb;
                            // a ZZ is represented as a sequence of limbs.

#define NTL_SP_NBITS (...)  // max number of bits in a "single-precision" number

#define NTL_WSP_NBITS (...)  // max number of bits in a "wide single-precision"
                             // number

// The following relations hold:
//    30 <= NTL_SP_NBITS <= NTL_WSP_NBITS 
//       <= min(NTL_ZZ_NBITS, NTL_BITS_PER_LONG-2)

// Note that NTL_ZZ_NBITS may be less than, equal to, or greater than
// NTL_BITS_PER_LONG  -- no particular relationship should be assumed to hold.
// In particular, expressions like (1L << NTL_ZZ_BITS) might overflow.
//
// "single-precision" numbers are meant to be used in conjunction with the
//  single-precision modular arithmetic routines.
//
// "wide single-precision" numbers are meant to be used in conjunction
//  with the ZZ arithmetic routines for optimal efficiency.

// The following auxiliary macros are also defined

#define NTL_FRADIX (...) // double-precision value of 2^NTL_ZZ_NBITS

#define NTL_SP_BOUND (1L << NTL_SP_NBITS)
#define NTL_WSP_BOUND (1L << NTL_WSP_NBITS)


// Backward compatibility notes:
//
// Prior to version 5.0, the macro NTL_NBITS was defined,
// along with the macro NTL_RADIX defined to be (1L << NTL_NBITS).
// While these macros are still available when using NTL's traditional 
// long integer package (i.e., when NTL_GMP_LIP is not set), 
// they are not available when using the GMP as the primary long integer 
// package (i.e., when NTL_GMP_LIP is set).
// Furthermore, when writing portable programs, one should avoid these macros.
// Note that when using traditional long integer arithmetic, we have
//    NTL_ZZ_NBITS = NTL_SP_NBITS = NTL_WSP_NBITS = NTL_NBITS.
//
// Prior to version 9.0, one could also assume that 
//   NTL_SP_NBITS <= NTL_DOUBLE_PRECISION-3;
// however, this is no longer the case (unless NTL is build with he NTL_LEGACY_SP_MULMOD
// flag turned on).


// Here are some additional functions.

void clear(ZZ& x); // x = 0
void set(ZZ& x);   // x = 1

void swap(ZZ& x, ZZ& y);
// swap x and y (done by "pointer swapping", if possible).

double log(const ZZ& a);
// returns double precision approximation to log(a)

long NextPowerOfTwo(long m);
// returns least nonnegative k such that 2^k >= m

long ZZ::size() const;
// a.size() returns the number of limbs of |a|; the
// size of 0 is 0.

void ZZ::SetSize(long k)
// a.SetSize(k) does not change the value of a, but simply pre-allocates
// space for k limbs.

long ZZ::SinglePrecision() const;
// a.SinglePrecision() is a predicate that tests if abs(a) < NTL_SP_BOUND

long ZZ::WideSinglePrecision() const;
// a.WideSinglePrecision() is a predicate that tests if abs(a) < NTL_WSP_BOUND

long digit(const ZZ& a, long k);
// returns k-th limb of |a|, position 0 being the low-order
// limb.
// OBSOLETE: this routine is only available when using NTL's traditional
// long integer arithmetic, and should not be used in programs
// that are meant to be portable. You should instead use the 
// routine ZZ_limbs_get, defined in ZZ_limbs.h.

void ZZ::kill();
// a.kill() sets a to zero and frees the space held by a.

void ZZ::swap(ZZ& x);
// swap method (done by "pointer swapping" if possible)

ZZ::ZZ(INIT_SIZE_TYPE, long k);
// ZZ(INIT_SIZE, k) initializes to 0, but space is pre-allocated so
// that numbers x with x.size() <= k can be stored without
// re-allocation.

static const ZZ& ZZ::zero();
// ZZ::zero() yields a read-only reference to zero, if you need it.




/**************************************************************************\

                    Small Prime Generation

primes are generated in sequence, starting at 2, and up to a maximum
that is no more than min(NTL_SP_BOUND, 2^30).

Example: print the primes up to 1000

#include <NTL/ZZ.h>

main()
{
   PrimeSeq s;
   long p;

   p = s.next();
   while (p <= 1000) {
      cout << p << "\n";
      p = s.next();
   }
}

\**************************************************************************/



class PrimeSeq {
public:
   PrimeSeq();
   ~PrimeSeq();

   long next();
   // returns next prime in the sequence.  returns 0 if list of small
   // primes is exhausted.

   void reset(long b);
   // resets generator so that the next prime in the sequence is the
   // smallest prime >= b.

private:
   PrimeSeq(const PrimeSeq&);        // disabled
   void operator=(const PrimeSeq&);  // disabled

};


ntl-11.5.1/doc/ZZ_limbs.cpp.html0000644417616742025610000000657614064716023020141 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_limbs.cpp.html
/**************************************************************************\

MODULE: ZZ_limbs

SUMMARY:

Defines low-level access to the "limbs" of a ZZ.

\**************************************************************************/


#include <NTL/ZZ.h>

#ifdef NTL_GMP_LIP
#include <gmp.h>
#endif
// NOTE: unlike other NTL header files, this one needs access
// to GMP's header file, which means that C++ files that include
// this file will need to ensure that the compiler has the 
// right "include path" to get at GMP's header file.


typedef ... ZZ_limb_t;
// The type of a limb. 
// With GMP, this is mp_limb_t, wich is usually (but not always) 
// typedef'd to unsigned long.
// Without GMP, this is unisigned long (although that is subject to change).
// In any case, all that one should assume is that this is an 
// unisgned integral type.

#define NTL_BITS_PER_LIMB_T (...)
// Integral constant defining the number of bits of ZZ_limb_t.

const ZZ_limb_t * ZZ_limbs_get(const ZZ& a);
// Get a pointer to the limbs of a (possibly null).
// The number of limbs can be obtained by invoking a.size().

void ZZ_limbs_set(ZZ& x, const ZZ_limb_t *p, long n);
// Sets the limbs of x to p[0..n-1].
// An error is raised on n < 0 or p == NULL and n > 0.
// It will work correctly even if p points to a limb of x
// itself.




ntl-11.5.1/doc/ZZVec.cpp.html0000644417616742025610000001071514064716023017377 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZVec.cpp.html

/**************************************************************************\

MODULE: ZZVec

SUMMARY:

The class ZZVec implements vectors of fixed-length ZZ's.  You can
allocate a vector of ZZ's of a specified length, where the maximum
size of each ZZ is also specified.  The size is measured in terms
of the number of limbs.

These parameters can be specified either with a constructor 
or with SetSize.  It is an error to try to re-size a vector of non-zero length,
or store a ZZ that doesn't fit.  The space can be released with "kill", 
and then you are free to call SetSize again.  

If you want more flexible---but less efficient---vectors, use vec_ZZ.

\**************************************************************************/

#include <NTL/ZZ.h>


class ZZVec {
public:
   ZZVec();

   ZZVec& operator=(const ZZVec&);
   // first kill()'s destination (unless source and destination are
   // identical)

   ZZVec(const ZZVec&);

   ~ZZVec();

   ZZVec(ZZVec&& other) noexcept;
   ZZVec& operator=(ZZVec&& other) noexcept;
   // move semantics (C++11 only)

   ZZVec(long n, long d);
   // sets length to n and max size of each element to d

   void SetSize(long n, long d);
   // sets length to n and max size of each element to d

   long length() const;
   // length of vector

   long BaseSize() const;
   // max size of each element

   void kill();
   // release space


   ZZ* elts();
   const ZZ* elts() const;
   // pointer to first element

   ZZ& operator[](long i);
   const ZZ& operator[](long i) const;
   // indexing operator; starts at 0; no range checking

   swap(ZZVec& x);
   // swap with x by swapping pointers

   void move(ZZVec& other);
   // quick move other to *this
};


void swap(ZZVec& x, ZZVec& y);
// swaps x and y by swapping pointers

ntl-11.5.1/doc/ZZX.cpp.html0000644417616742025610000010717614064716023017101 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZX.cpp.html


/**************************************************************************\

MODULE: ZZX

SUMMARY:

The class ZZX implements polynomials in ZZ[X], i.e., univariate
polynomials with integer coefficients.

Polynomial multiplication is implemented using one of 4 different
algorithms:

1) classical 

2) Karatsuba

3) Schoenhage & Strassen --- performs an FFT by working
     modulo a "Fermat number" of appropriate size...
     good for polynomials with huge coefficients
     and moderate degree

4) CRT/FFT --- performs an FFT by working modulo several
     small primes...good for polynomials with moderate coefficients
     and huge degree.

The choice of algorithm is somewhat heuristic, and may not always be
perfect.

Many thanks to Juergen Gerhard <jngerhar@plato.uni-paderborn.de> for
pointing out the deficiency in the NTL-1.0 ZZX arithmetic, and for
contributing the Schoenhage/Strassen code.

Extensive use is made of modular algorithms to enhance performance
(e.g., the GCD algorithm and amny others).

\**************************************************************************/

#include <NTL/vec_ZZ.h>
#include "zz_pX.h"
#include <NTL/ZZ_pX.h>


class ZZX {
public:


   ZZX(); // initial value 0

   ZZX(const ZZX& a); // copy
   explicit ZZX(const ZZ& a); // promotion
   explicit ZZX(long a); // promotion

   ~ZZX();


   ZZX(ZZX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

   ZZX& operator=(ZZX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set


   ZZX(INIT_MONO_TYPE, long i, const ZZ& c);
   ZZX(INIT_MONO_TYPE, long i, long c);
   // initial value c*X^i, invoke as ZZX(INIT_MONO, i, c)

   ZZX(INIT_MONO_TYPE, long i);
   // initial value X^i, invoke as ZZX(INIT_MONO, i)

   ZZX& operator=(const ZZX& a); // assignment
   ZZX& operator=(const ZZ& a);
   ZZX& operator=(long a);

   typedef ZZ coeff_type;

   // ...

};




/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZX& a);  // return deg(a); deg(0) == -1.

const ZZ& coeff(const ZZX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ& LeadCoeff(const ZZX& a);
// returns leading term of a, or zero if a == 0

const ZZ& ConstTerm(const ZZX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZX& x, long i, const ZZ& a);
void SetCoeff(ZZX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZX& x); // x is set to the monomial X

long IsX(const ZZX& a); // test if x = X




ZZ& ZZX::operator[](long i);
const ZZ& ZZX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void ZZX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.







/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const ZZX& a, const ZZX& b);
long operator!=(const ZZX& a, const ZZX& b);

long IsZero(const ZZX& a);  // test for 0
long IsOne(const ZZX& a);  // test for 1

// PROMOTIONS: operators ==, != promote {long, ZZ} to ZZX on (a, b).


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

ZZX operator+(const ZZX& a, const ZZX& b);
ZZX operator-(const ZZX& a, const ZZX& b);
ZZX operator-(const ZZX& a); // unary -

ZZX& operator+=(ZZX& x, const ZZX& a);
ZZX& operator-=(ZZX& x, const ZZX& a);

ZZX& operator++(ZZX& x);  // prefix
void operator++(ZZX& x, int);  // postfix

ZZX& operator--(ZZX& x);  // prefix
void operator--(ZZX& x, int);  // postfix


// procedural versions:

void add(ZZX& x, const ZZX& a, const ZZX& b); // x = a + b
void sub(ZZX& x, const ZZX& a, const ZZX& b); // x = a - b
void negate(ZZX& x, const ZZX& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, ZZ} 
// to ZZX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZX operator*(const ZZX& a, const ZZX& b);

ZZX& operator*=(ZZX& x, const ZZX& a);


// procedural versions:

void mul(ZZX& x, const ZZX& a, const ZZX& b); // x = a * b

void sqr(ZZX& x, const ZZX& a); // x = a^2
ZZX sqr(const ZZX& a);

// PROMOTIONS: operator * and procedure mul promote {long, ZZ} to ZZX 
// on (a, b).


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZX operator<<(const ZZX& a, long n);
ZZX operator>>(const ZZX& a, long n);

ZZX& operator<<=(ZZX& x, long n);
ZZX& operator>>=(ZZX& x, long n);

// procedural versions:

void LeftShift(ZZX& x, const ZZX& a, long n);
ZZX LeftShift(const ZZX& a, long n);

void RightShift(ZZX& x, const ZZX& a, long n);
ZZX RightShift(const ZZX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/


// Given polynomials a, b in ZZ[X], there exist polynomials
// q, r in QQ[X] such that a = b*q + r, deg(r) < deg(b).
// These routines return q and/or r if q and/or r lie(s) in ZZ[X],
// and otherwise raise an error.  

// Note that if the leading coefficient of b is 1 or -1, 
// then q and r always lie in ZZ[X], and no error can occur.

// For example, you can write f/2 for a ZZX f.  If all coefficients
// of f are even, the result is f with a factor of two removed;
// otherwise, an error is raised.  More generally, f/g will be
// evaluate q in ZZ[X] such that f = q*g if such a q exists,
// and will otherwise raise an error.

// See also below the routines for pseudo-division and division
// predicates for routines that are perhaps more useful in
// some situations.


// operator notation: 

ZZX operator/(const ZZX& a, const ZZX& b);
ZZX operator/(const ZZX& a, const ZZ& b);
ZZX operator/(const ZZX& a, long b);

ZZX operator%(const ZZX& a, const ZZX& b);

ZZX& operator/=(ZZX& x, const ZZX& b);
ZZX& operator/=(ZZX& x, const ZZ& b);
ZZX& operator/=(ZZX& x, long b);

ZZX& operator%=(ZZX& x, const ZZX& b);


// procedural versions:

void DivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b);
// computes q, r such that a = b q + r and deg(r) < deg(b).

void div(ZZX& q, const ZZX& a, const ZZX& b);
void div(ZZX& q, const ZZX& a, const ZZ& b);
void div(ZZX& q, const ZZX& a, long b);
// same as DivRem, but only computes q

void rem(ZZX& r, const ZZX& a, const ZZX& b);
// same as DivRem, but only computes r



// divide predicates:

long divide(ZZX& q, const ZZX& a, const ZZX& b);
long divide(ZZX& q, const ZZX& a, const ZZ& b);
long divide(ZZX& q, const ZZX& a, long b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


long divide(const ZZX& a, const ZZX& b);
long divide(const ZZX& a, const ZZ& b);
long divide(const ZZX& a, long b);
// if b | a, returns 1; otherwise returns 0

// These algorithms employ a modular approach, performing the division
// modulo small primes (reconstructing q via the CRT).  It is
// usually much faster than the general division routines above
// (especially when b does not divide a).


void content(ZZ& d, const ZZX& f);
ZZ content(const ZZX& f);
// d = content of f, sign(d) == sign(LeadCoeff(f)); content(0) == 0

void PrimitivePart(ZZX& pp, const ZZX& f);
ZZX PrimitivePart(const ZZX& f);
// pp = primitive part of f, LeadCoeff(pp) >= 0; PrimitivePart(0) == 0



// pseudo-division:

void PseudoDivRem(ZZX& q, ZZX& r, const ZZX& a, const ZZX& b);
// performs pseudo-division: computes q and r with deg(r) < deg(b),
// and LeadCoeff(b)^(deg(a)-deg(b)+1) a = b q + r.  Only the classical
// algorithm is used.

void PseudoDiv(ZZX& q, const ZZX& a, const ZZX& b);
ZZX PseudoDiv(const ZZX& a, const ZZX& b);
// same as PseudoDivRem, but only computes q

void PseudoRem(ZZX& r, const ZZX& a, const ZZX& b);
ZZX PseudoRem(const ZZX& a, const ZZX& b);
// same as PseudoDivRem, but only computes r


/**************************************************************************\

                                  GCD's

\**************************************************************************/


void GCD(ZZX& d, const ZZX& a, const ZZX& b);
ZZX GCD(const ZZX& a, const ZZX& b);
// d = gcd(a, b), LeadCoeff(d) >= 0.  Uses a modular algorithm.


void XGCD(ZZ& r, ZZX& s, ZZX& t, const ZZX& a, const ZZX& b,
          long deterministic=0);
// r = resultant of a and b; if r != 0, then computes s and t such
// that: a*s + b*t = r; otherwise s and t not affected.  if
// !deterministic, then resultant computation may use a randomized
// strategy that errs with probability no more than 2^{-80}.



/**************************************************************************\

                               Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.


\**************************************************************************/


istream& operator>>(istream& s, ZZX& x);
ostream& operator<<(ostream& s, const ZZX& a);


/**************************************************************************\

                             Some utility routines

\**************************************************************************/


void diff(ZZX& x, const ZZX& a); // x = derivative of a
ZZX diff(const ZZX& a);

long MaxBits(const ZZX& f);
// returns max NumBits of coefficients of f

void reverse(ZZX& x, const ZZX& a, long hi);
ZZX reverse(const ZZX& a, long hi);

void reverse(ZZX& x, const ZZX& a);
ZZX reverse(const ZZX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version


void VectorCopy(vec_ZZ& x, const ZZX& a, long n);
vec_ZZ VectorCopy(const ZZX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.



/**************************************************************************\

                       Arithmetic mod X^n

All routines require n >= 0, otherwise an error is raised.

\**************************************************************************/


void trunc(ZZX& x, const ZZX& a, long m); // x = a % X^m
ZZX trunc(const ZZX& a, long m);

void MulTrunc(ZZX& x, const ZZX& a, const ZZX& b, long n);
ZZX MulTrunc(const ZZX& a, const ZZX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZX& x, const ZZX& a, long n);
ZZX SqrTrunc(const ZZX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZX& x, const ZZX& a, long n);
ZZX InvTrunc(const ZZX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.




/**************************************************************************\

                               Modular Arithmetic

The modulus f must be monic with deg(f) > 0, 
and other arguments must have smaller degree.

\**************************************************************************/

void MulMod(ZZX& x, const ZZX& a, const ZZX& b, const ZZX& f);
ZZX MulMod(const ZZX& a, const ZZX& b, const ZZX& f);
// x = a * b mod f

void SqrMod(ZZX& x, const ZZX& a, const ZZX& f);
ZZX SqrMod(const ZZX& a, const ZZX& f);
// x = a^2 mod f

void MulByXMod(ZZX& x, const ZZX& a, const ZZX& f);
ZZX MulByXMod(const ZZX& a, const ZZX& f);
// x = a*X mod f


/**************************************************************************\

                  traces, norms, resultants, discriminants,
                   minimal and characteristic polynomials

\**************************************************************************/


void TraceMod(ZZ& res, const ZZX& a, const ZZX& f);
ZZ TraceMod(const ZZX& a, const ZZX& f);
// res = trace of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f)

void TraceVec(vec_ZZ& S, const ZZX& f);
vec_ZZ TraceVec(const ZZX& f);
// S[i] = Trace(X^i mod f), for i = 0..deg(f)-1.
// f must be a monic polynomial.


// The following routines use a modular approach.

void resultant(ZZ& res, const ZZX& a, const ZZX& b, long deterministic=0);
ZZ resultant(const ZZX& a, const ZZX& b, long deterministic=0);
// res = resultant of a and b. If !deterministic, then it may use a
// randomized strategy that errs with probability no more than
// 2^{-80}.



void NormMod(ZZ& res, const ZZX& a, const ZZX& f, long deterministic=0);
ZZ NormMod(const ZZX& a, const ZZX& f, long deterministic=0);
// res = norm of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f). If !deterministic, then it may use a randomized strategy
// that errs with probability no more than 2^{-80}.



void discriminant(ZZ& d, const ZZX& a, long deterministic=0);
ZZ discriminant(const ZZX& a, long deterministic=0);
// d = discriminant of a = (-1)^{m(m-1)/2} resultant(a, a')/lc(a),
// where m = deg(a). If !deterministic, then it may use a randomized
// strategy that errs with probability no more than 2^{-80}.


void CharPolyMod(ZZX& g, const ZZX& a, const ZZX& f, long deterministic=0);
ZZX CharPolyMod(const ZZX& a, const ZZX& f, long deterministic=0);
// g = char poly of (a mod f).  f must be monic.  If !deterministic,
// then it may use a randomized strategy that errs with probability no
// more than 2^{-80}.


void MinPolyMod(ZZX& g, const ZZX& a, const ZZX& f);
ZZX MinPolyMod(const ZZX& a, const ZZX& f);
// g = min poly of (a mod f).  f must be monic, 0 < deg(f), deg(a) <
// deg(f).  May use a probabilistic strategy that errs with
// probability no more than 2^{-80}.




/**************************************************************************\

                  Incremental Chinese Remaindering

\**************************************************************************/

long CRT(ZZX& a, ZZ& prod, const zz_pX& A);
long CRT(ZZX& a, ZZ& prod, const ZZ_pX& A);
// Incremental Chinese Remaindering: If p is the current zz_p/ZZ_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.





/**************************************************************************\

                                vectors of ZZX's

\**************************************************************************/


typedef Vec<ZZX> vec_ZZX; // backward compatibility


/**************************************************************************\

                                Miscellany


\**************************************************************************/


void clear(ZZX& x); // x = 0
void set(ZZX& x); // x = 1

void ZZX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

ZZX::ZZX(INIT_SIZE_TYPE, long n);
// ZZX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZX& zero();
// ZZX::zero() is a read-only reference to 0

void ZZX::swap(ZZX& x);
void swap(ZZX& x, ZZX& y);
// swap (by swapping pointers)


ZZX::ZZX(long i, const ZZ& c);
ZZX::ZZX(long i, long c);
// initial value c*X^i, provided for backward compatibility
ntl-11.5.1/doc/ZZXFactoring.cpp.html0000644417616742025610000002727014064716023020732 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZXFactoring.cpp.html

/*****************************************************************************\

MODULE: ZZXFactoring

SUMMARY:

Routines are provided for factoring in ZZX.

See IMPLEMENTATION DETAILS below for a discussion of the algorithms used,
and of the flags available for selecting among these algorithms.

\*****************************************************************************/

#include <NTL/ZZX.h>
#include <NTL/pair_ZZX_long.h>

void SquareFreeDecomp(vec_pair_ZZX_long& u, const ZZX& f);
const vector(pair_ZZX_long SquareFreeDecomp(const ZZX& f);

// input is primitive, with positive leading coefficient.  Performs
// square-free decomposition.  If f = prod_i g_i^i, then u is set to a
// lest of pairs (g_i, i).  The list is is increasing order of i, with
// trivial terms (i.e., g_i = 1) deleted.


void MultiLift(vec_ZZX& A, const vec_zz_pX& a, const ZZX& f, long e,
               long verbose=0);

// Using current value p of zz_p::modulus(), this lifts the
// square-free factorization a mod p of f to a factorization A mod p^e
// of f.  It is required that f and all the polynomials in a are
// monic.



void SFFactor(vec_ZZX& factors, const ZZX& f, long verbose=0, long bnd=0);
vec_ZZX SFFactor(const ZZX& f, long verbose=0, long bnd=0);

// input f is primitive and square-free, with positive leading
// coefficient.  bnd, if not zero, indicates that f divides a
// polynomial h whose Euclidean norm is bounded by 2^{bnd} in absolute
// value.  This uses the routine SFCanZass in zz_pXFactoring and then
// performs a MultiLift, followed by a brute-force search for the
// factors.  

// A number of heuristics are used to speed up the factor-search step.
// See "implementation details" below.


void factor(ZZ& c,
            vec_pair_ZZX_long& factors,
            const ZZX& f,
            long verbose=0,
            long bnd=0);

// input f is is an arbitrary polynomial.  c is the content of f, and
// factors is the facrorization of its primitive part.  bnd is as in
// SFFactor.  The routine calls SquareFreeDecomp and SFFactor.

void mul(ZZX& x, const vec_pair_ZZX_long& a);
ZZX mul(const vec_pair_ZZX_long& a);
// multiplies polynomials, with multiplcities.




/*****************************************************************************\

IMPLEMENTATION DETAILS

To factor a polynomial, first its content is extracted, and it is
made squarefree.  This is typically very fast.

Second, a simple hack is performed: if the polynomial is of the
form g(x^l), then an attempt is made to factor g(k^m),
for divisors m of l, which can in some cases greatly simplify
the factorization task.
You can turn this "power hack" on/off by setting the following variable
to 1/0:

   extern thread_local long ZZXFac_PowerHack;  // initial value = 1


Third, the polynomial is factored modulo several
small primes, and one small prime p is selected as the "best".
You can choose the number of small primes that you want to use
by setting the following variable:

   extern thread_local long ZZXFac_InitNumPrimes;  // initial value = 7

Fourth, The factorization mod p is "lifted" to a factorization mod p^k
for a sufficiently large k.  This is done via quadratic Hensel
lifting.  Despite "folk wisdom" to the contrary, this is much
more efficient than linear Hensel lifting, especially since NTL
has very fast polynomial arithmetic.

After the "lifting phase" comes the "factor recombination phase".
The factorization mod p^k may be "finer" than the true factorization
over the integers, hence we have to "combine" subsets of modular factors
and test if these are factors over the integers.

There are two basic strategies:  the "Zassenhaus" method
and the "van Hoeij" method.

The van Hoeij method:

The van Hoeij method is fairly new, but it is so much better than
the older, Zassenhaus method, that it is now the default.
For a description of the method, go to Mark van Hoeij's home page:

   http://www.openmath.org/~hoeij/

The van Hoeij method is not really a specific algorithm, but a general
algorithmic approach: many parameters and strategies have to be selected
to obtain a specific algorithm, and it is a challenge to
make all of these choices so that the resulting algorithm works
fairly well on all input polynomials.

Set the following variable to 1 to enable the van Hoeij method,
and to 0 to revert to the Zassenhaus method:

   extern thread_local long ZZXFac_van_Hoeij; // initial value = 1

Note that the "power hack" is still on by default when using van Hoeij's
method, but we have arranged things so that the "power hack" strategy 
is abandoned if it appears to be too much a waste of time.
Unlike with the Zassenhaus method, using the "power hack" method with
van Hoeij can sometimes be a huge waste of time if one is not careful.



The Zassenhaus method:

The Zassenhaus method is essentially a brute-force search, but with
a lot of fancy "pruning" techniques, as described in the paper
[J. Abbott, V. Shoup, P. Zimmermann, "Factoring in Z[x]: the searching phase",
ISSAC 2000].

These heuristics are fairly effective, and allow one to easily deal
with up to around 30-40 modular factors, which is *much* more
than other Zassenhaus-based factorizers can deal with; however, after this, 
the exponential behavior of the algorithm really starts to dominate.

The behaviour of these heuristics can be fine tuned by
setting the following global variables:

   extern thread_local long ZZXFac_MaxNumPrimes;  // initial value = 50
   // During the factor recombination phase, if not much progress
   // is being made, occasionally more "local" information is 
   // collected by factoring f modulo another prime.
   // This "local" information is used to rule out degrees 
   // of potential factors during recombination.
   // This value bounds the total number of primes modulo which f 
   // is factored.

   extern thread_local long ZZXFac_MaxPrune;  // initial value = 10
   // A kind of "meet in the middle" strategy is used
   // to prune the search space during recombination.
   // For many (but not all) polynomials, this can greatly
   // reduce the running time.
   // When it does work, there is a time-space tradeoff:
   // If t = ZZXFac_MaxPrune, the running time will be reduced by a factor near
   // 2^t, but the table will take (at most) t*2^(t-1) bytes of storage.
   // Note that ZZXFac_MaxPrune is treated as an upper bound on t---the
   // factoring algorithm may decide to use a smaller value of t for
   // a number of reasons.



\*****************************************************************************/
ntl-11.5.1/doc/ZZ_p.cpp.html0000644417616742025610000005515114064716023017263 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_p.cpp.html


/**************************************************************************\

MODULE: ZZ_p

SUMMARY:

The class ZZ_p is used to represent integers mod p.  The modulus p may
be any positive integer, not necessarily prime.  

Objects of the class ZZ_p are represented as a ZZ in the range 0..p-1.

An executing program maintains a "current modulus", which is set to p using
ZZ_p::init(p).  The current modulus *must* be initialized before any operations
on ZZ_p's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes ZZ_pPush and ZZ_pContext below).


\**************************************************************************/

#include <NTL/ZZ.h>
#include <NTL/ZZVec.h>
#include <NTL/SmartPtr.h>

class ZZ_p {
public:

   ZZ_p(); // initialize to 0

   ZZ_p(const ZZ_p& a); // copy constructor
   explicit ZZ_p(long a);  // promotion constructor

   ~ZZ_p(); // destructor

   ZZ_p& operator=(const ZZ_p& a); // assignment
   ZZ_p& operator=(long a); // assignment

   ZZ_p(ZZ_p&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

   ZZ_p& operator=(ZZ_p&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

   static void init(const ZZ& p);
   // ZZ_p::init(p) sets the modulus to p (p > 1)

   static const ZZ& modulus();
   // ZZ_p::modulus() yields read-only reference to the current
   // modulus

   // typedefs to aid in generic programming
   typedef ZZ rep_type;
   typedef ZZ_pContext context_type;
   typedef ZZ_pBak bak_type;
   typedef ZZ_pPush push_type;
   typedef ZZ_pX poly_type;
};


/**************************************************************************\

                      Access to representation

\**************************************************************************/


const ZZ& rep(const ZZ_p& a);
// read-only access to representation of a

/****** Example: ********  

   ZZ x;
   ZZ_p a;

   x = rep(a);

*************************/


/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_p& a, const ZZ_p& b);
long operator!=(const ZZ_p& a, const ZZ_p& b);

// PROMOTIONS: the comparison operators provide promotions
// from long to ZZ_p on (a, b)

long IsZero(const ZZ_p& a);  // test for 0
long IsOne(const ZZ_p& a);  // test for 1


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

ZZ_p operator+(const ZZ_p& a, const ZZ_p& b);
ZZ_p operator-(const ZZ_p& a, const ZZ_p& b);
ZZ_p operator-(const ZZ_p& a); // unary -

ZZ_p& operator+=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator+=(ZZ_p& x, long b);

ZZ_p& operator-=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator-=(ZZ_p& x, long b);

ZZ_p& operator++(ZZ_p& x);  // prefix
void operator++(ZZ_p& x, int);  // postfix

ZZ_p& operator--(ZZ_p& x);  // prefix
void operator--(ZZ_p& x, int);  // postfix

// procedural versions:


void add(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a + b
void sub(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a - b 
void negate(ZZ_p& x, const ZZ_p& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub provide promotions
// from long to ZZ_p on (a, b)


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

ZZ_p operator*(const ZZ_p& a, const ZZ_p& b);

ZZ_p& operator*=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator*=(ZZ_p& x, long b);

// procedural versions:


void mul(ZZ_p& x, const ZZ_p& a, const ZZ_p& b); // x = a * b

void sqr(ZZ_p& x, const ZZ_p& a); // x = a^2
ZZ_p sqr(const ZZ_p& a); // x = a^2

// PROMOTIONS: operator * and procedure mul provide promotions 
// from long to ZZ_p on (a, b)



/**************************************************************************\

                              Division

\**************************************************************************/


// operator notation:

ZZ_p operator/(const ZZ_p& a, const ZZ_p& b);

ZZ_p& operator/=(ZZ_p& x, const ZZ_p& b);
ZZ_p& operator/=(ZZ_p& x, long b);


// procedural versions:


void div(ZZ_p& x, const ZZ_p& a, const ZZ_p& b);
// x = a/b.

// By default, if b is not invertible, an error is raised.  
// If exceptions are enabled, an InvModErrorObject is thrown
// (see documentation in the ZZ module); otherwise, the program
// aborts with an error message.
// For backward compatibility, one can define an error handler
// void H(const ZZ_p& b), and setting ZZ_p::DivHandler = H.  Then if b
// != 0 and b is not invertible, the function H is invoked with b as
// its argument.  If the error handler function returns to its caller,
// error handling proceeds as described above.

void inv(ZZ_p& x, const ZZ_p& a); // x = 1/a
ZZ_p inv(const ZZ_p& a);

// Error handling is the same as above.

// PROMOTIONS: operator / and procedure div provide promotions
// from long to ZZ_p on (a, b)



/**************************************************************************\

                            Exponentiation

\**************************************************************************/



void power(ZZ_p& x, const ZZ_p& a, const ZZ& e); // x = a^e (e may be negative)
ZZ_p power(const ZZ_p& a, const ZZ& e); // functional variants

void power(ZZ_p& x, const ZZ_p& a, long e);
ZZ_p power(ZZ_p& x, const ZZ_p& a, long e);



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(ZZ_p& x);
ZZ_p random_ZZ_p();
// x = random element in ZZ_p.  


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const ZZ_p& a);

istream& operator>>(istream& s, ZZ_p& x);
// a ZZ is read and reduced mod p

/**************************************************************************\

                       Modulus Switching 


A class ZZ_pPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to p, and automatically restore it:

   { 
      ZZ_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      ZZ_pPush push; // just backup current modulus

        ...

      ZZ_p::init(p1); // install p1 

        ...

      ZZ_p::init(p2); // install p2

      // reinstall original modulus at close of scope
   }

      
The ZZ_pPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see ZZ_pContext below.  There is also an older ZZ_pBak class
that may also be useful.

..........................................................................

It is critical that ZZ_p objects created under one ZZ_p modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
ZZ_p modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any ZZ_p object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


NOTE: the implementation of Vec<ZZ_p> is specialized to manage memory more
efficiently than in the default implementation of Vec<T>.  Specifically,
contiguous elements in a Vec<ZZ_p> are allocated in a contiguous region of
memory.  This reduces the number of calls to the memory allocator, and --- more
significantly --- leads to greater locality of reference.  A consequence of
this implementation is that any calls to SetLength on a Vec<ZZ_p> object will
need to use information about the current modulus, and so such calls should
only be done "in context".  That said, it is still safe to construct a
Vec<ZZ_p> using the default or copy contructor, and to assign or append one
Vec<ZZ_p> to another "out of context".

\**************************************************************************/



// A convenient interface for common cases:

class ZZ_pPush {

public:
ZZ_pPush();  // backup current modulus
explicit ZZ_pPush(const ZZ& p);
explicit ZZ_pPush(const ZZ_pContext& context);
  // backup current modulus and install the given one

private:
ZZ_pPush(const ZZ_pPush&); // disabled
void operator=(const ZZ_pPush&); // disabled

};



// more general context switching:
// A ZZ_pContext object has a modulus q (possibly "null")

class ZZ_pContext {


public:

ZZ_pContext(); // q = "null"

explicit ZZ_pContext(const ZZ& p);  // q = p

void save(); // q = CurrentModulus
void restore() const; // CurrentModulus = q

ZZ_pContext(const ZZ_pContext&);  // copy
ZZ_pContext& operator=(const ZZ_pContext&); // assignment
~ZZ_pContext(); // destructor


};


// An older interface:
// To describe this logic, think of a ZZ_pBak object
// of having two components: a modulus q (possibly "null") and 
// an "auto-restore bit" b.

class ZZ_pBak {
public:


   ZZ_pBak();  // q = "null", b = 0

   ~ZZ_pBak();  // if (b) CurrentModulus = q

   void save();  // q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = q, b = 0


private:
   ZZ_pBak(const ZZ_pBak&);  // copy disabled
   void operator=(const ZZ_pBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(ZZ_p& x); // x = 0
void set(ZZ_p& x); // x = 1

static long ZZ_p::ModulusSize();
//  ZZ_p::ModulusSize() returns ZZ_p::modulus().size()

static const ZZ_p& ZZ_p::zero();
// ZZ_p::zero() yields a read-only reference to zero

void swap(ZZ_p& x, ZZ_p& y);
// swap x and y (done by "pointer swapping", if possible).

void ZZ_p::swap(ZZ& x);
// swap member function


ZZ_p::ZZ_p(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as ZZ_p x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

ZZ_p::ZZ_p(INIT_ALLOC_TYPE);
// special constructor: invoke as ZZ_p x(INIT_ALLOC);
// initializes x to 0, but allocates space


ZZ_p::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-11.5.1/doc/ZZ_pE.cpp.html0000644417616742025610000005321114064716023017363 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_pE.cpp.html


/**************************************************************************\

MODULE: ZZ_pE

SUMMARY:

The class ZZ_pE is used to represent polynomials in Z_p[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  The modulus p defining Z_p need
not be prime either.

Objects of the class ZZ_pE are represented as a ZZ_pX of degree < deg(P).

An executing program maintains a "current modulus", which is set to P
using ZZ_pE::init(P).  The current modulus for ZZ_pE (as well as for ZZ_p)
*must* be initialized before an operations on ZZ_pE's are performed.

The modulus may be changed, and a mechanism is provided for saving and
restoring a modulus (see classes ZZ_pEPush and ZZ_pEContext below).


\**************************************************************************/

#include <NTL/ZZ_pX.h>

class ZZ_pE {
public:

   ZZ_pE(); // initial value 0

   ZZ_pE(const ZZ_pE& a); // copy constructor
   explicit ZZ_pE(const ZZ_p& a); // promotion
   explicit ZZ_pE(long a); // promotion

   ZZ_pE& operator=(const ZZ_pE& a); // assignment
   ZZ_pE& operator=(const ZZ_p& a); // assignment
   ZZ_pE& operator=(long a); // assignment

   ~ZZ_pE(); // destructor

   ZZ_pE(ZZ_pE&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   ZZ_pE& operator=(ZZ_pE&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   static void init(const ZZ_pX& P);
   // ZZ_pE::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const ZZ_pXModulus& modulus();
   // ZZ_pE::modulus() yields read-only reference to the current modulus 

   static long degree();
   // ZZ_pE::degree() returns deg(P)


   // typedefs to aid generic programming
   typedef ZZ_pX rep_type;
   typedef ZZ_pEContext context_type;
   typedef ZZ_pEBak bak_type;
   typedef ZZ_pEPush push_type;
   typedef ZZ_pEX poly_type;

};


const ZZ_pX& rep(const ZZ_pE& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const ZZ_pE& a, const ZZ_pE& b);
long operator!=(const ZZ_pE& a, const ZZ_pE& b);

long IsZero(const ZZ_pE& a);  // test for 0
long IsOne(const ZZ_pE& a);  // test for 1

// PROMOTIONS: ==, != promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

ZZ_pE operator+(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE operator-(const ZZ_pE& a, const ZZ_pE& b);
ZZ_pE operator-(const ZZ_pE& a);

ZZ_pE& operator+=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator+=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator+=(ZZ_pE& x, long a);

ZZ_pE& operator++(ZZ_pE& x); // prefix
void operator++(ZZ_pE& x, int); // postfix

ZZ_pE& operator-=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator-=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator-=(ZZ_pE& x, long a);

ZZ_pE& operator--(ZZ_pE& x); // prefix
void operator--(ZZ_pE& x, int); // postfix

// procedural versions:

void add(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a + b
void sub(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a - b 
void negate(ZZ_pE& x, const ZZ_pE& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

ZZ_pE operator*(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE& operator*=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator*=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator*=(ZZ_pE& x, long a);

// procedural versions:


void mul(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b); // x = a * b

void sqr(ZZ_pE& x, const ZZ_pE& a); // x = a^2
ZZ_pE sqr(const ZZ_pE& a);

// PROMOTIONS: *, mul promote {long, ZZ_p} to ZZ_pE on (a, b).



/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

ZZ_pE operator/(const ZZ_pE& a, const ZZ_pE& b);

ZZ_pE& operator/=(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE& operator/=(ZZ_pE& x, const ZZ_p& a);
ZZ_pE& operator/=(ZZ_pE& x, long a);


// procedural versions:

void div(ZZ_pE& x, const ZZ_pE& a, const ZZ_pE& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(ZZ_pE& x, const ZZ_pE& a);
ZZ_pE inv(const ZZ_pE& a);
// x = 1/a

PROMOTIONS: /, div promote {long, ZZ_p} to ZZ_pE on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(ZZ_pE& x, const ZZ_pE& a, const ZZ& e);
ZZ_pE power(const ZZ_pE& a, const ZZ& e);

void power(ZZ_pE& x, const ZZ_pE& a, long e);
ZZ_pE power(const ZZ_pE& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(ZZ_pE& x);
ZZ_pE random_ZZ_pE();
// x = random element in ZZ_pE.

/**************************************************************************\

                               Norms and Traces

\**************************************************************************/



void trace(ZZ_p& x, const ZZ_pE& a);  // x = trace of a
ZZ_p trace(const ZZ_pE& a);

void norm(ZZ_p& x, const ZZ_pE& a);   // x = norm of a
ZZ_p norm(const ZZ_pE& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const ZZ_pE& a);

istream& operator>>(istream& s, ZZ_pE& x);
// a ZZ_pX is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class ZZ_pEPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      ZZ_pEPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      ZZ_pEPush push; // just backup current modulus

        ...

      ZZ_pE::init(P1); // install P1 

        ...

      ZZ_pE::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The ZZ_pEPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see ZZ_pEContext below.  There is also an older ZZ_pEBak class
that may also be useful.

..........................................................................

It is critical that ZZ_pE objects created under one ZZ_pE modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
ZZ_pE modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any ZZ_pE object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


\**************************************************************************/


// A convenient interface for common cases

class ZZ_pEPush {

public:
ZZ_pEPush();  // backup current modulus
explicit ZZ_pEPush(const ZZ_pX& P);
explicit ZZ_pEPush(const ZZ_pEContext& context);
  // backup current modulus and install the given one

private:
ZZ_pEPush(const ZZ_pEPush&); // disabled
void operator=(const ZZ_pEPush&); // disabled

};



// more general context switching:
// A ZZ_pEContext object has a modulus Q (possibly "null"),

class ZZ_pEContext {


public:

ZZ_pEContext(); // Q = "null"
explicit ZZ_pEContext(const ZZ_pX& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

ZZ_pEContext(const ZZ_pEContext&);  // copy
ZZ_pEContext& operator=(const ZZ_pEContext&); // assignment
~ZZ_pEContext(); // destructor


};


// An older interface:
// To describe this logic, think of a ZZ_pEBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class ZZ_pEBak {
public:


   ZZ_pEBak();  // Q = "null", b = 0

   ~ZZ_pEBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   ZZ_pEBak(const ZZ_pEBak&);  // copy disabled
   void operator=(const ZZ_pEBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(ZZ_pE& x); // x = 0
void set(ZZ_pE& x); // x = 1

static const ZZ_pE& ZZ_pE::zero();
// ZZ_pE::zero() yields a read-only reference to zero

void ZZ_pE::swap(ZZ_pE& x);
void swap(ZZ_pE& x, ZZ_pE& y);
// swap (done by "pointer swapping", if possible).

static ZZ& ZZ_pE::cardinality();
// yields the cardinality, i.e., p^{ZZ_pE::degree()}

ZZ_pE::ZZ_pE(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as ZZ_pE x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

ZZ_pE::ZZ_pE(INIT_ALLOC_TYPE);
// special constructor: invoke as ZZ_pE x(INIT_ALLOC);
// initializes x to 0, but allocates space

ZZ_pE::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-11.5.1/doc/ZZ_pEX.cpp.html0000644417616742025610000016037014064716023017520 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_pEX.cpp.html

/**************************************************************************\

MODULE: ZZ_pEX

SUMMARY:

The class ZZ_pEX represents polynomials over ZZ_pE,
and so can be used, for example, for arithmentic in GF(p^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
ZZ_pE need not be a field.

\**************************************************************************/

#include <NTL/ZZ_pE.h>
#include <NTL/vec_ZZ_pE.h>

class ZZ_pEX {
public:

   ZZ_pEX(); // initial value 0

   ZZ_pEX(const ZZ_pEX& a); // copy

   explicit ZZ_pEX(const ZZ_pE& a); // promotion
   explicit ZZ_pEX(const ZZ_p& a);
   explicit ZZ_pEX(long a);

   ZZ_pEX& operator=(const ZZ_pEX& a); // assignment
   ZZ_pEX& operator=(const ZZ_pE& a);
   ZZ_pEX& operator=(const ZZ_p& a);
   ZZ_pEX& operator=(long a);

   ~ZZ_pEX(); // destructor

   ZZ_pEX(ZZ_pEX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   ZZ_pEX& operator=(ZZ_pEX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_pE& c);
   ZZ_pEX(INIT_MONO_TYPE, long i, const ZZ_p& c);
   ZZ_pEX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as ZZ_pEX(INIT_MONO, i, c)

   ZZ_pEX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as ZZ_pEX(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef ZZ_pE coeff_type;
   typedef ZZ_pEXModulus modulus_type;

   // ...

};




/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZ_pEX& a);  // return deg(a); deg(0) == -1.

const ZZ_pE& coeff(const ZZ_pEX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ_pE& LeadCoeff(const ZZ_pEX& a);
// returns leading term of a, or zero if a == 0

const ZZ_pE& ConstTerm(const ZZ_pEX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZ_pEX& x, long i, const ZZ_pE& a);
void SetCoeff(ZZ_pEX& x, long i, const ZZ_p& a);
void SetCoeff(ZZ_pEX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZ_pEX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZ_pEX& x); // x is set to the monomial X

long IsX(const ZZ_pEX& a); // test if x = X




ZZ_pE& ZZ_pEX::operator[](long i);
const ZZ_pE& ZZ_pEX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void ZZ_pEX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZ_pEX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZ_pEX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.










/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_pEX& a, const ZZ_pEX& b);
long operator!=(const ZZ_pEX& a, const ZZ_pEX& b);

long IsZero(const ZZ_pEX& a); // test for 0
long IsOne(const ZZ_pEX& a); // test for 1

// PROMOTIONS: ==, != promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

ZZ_pEX operator+(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator-(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator-(const ZZ_pEX& a);

ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator+=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator+=(ZZ_pEX& x, long a);


ZZ_pEX& operator++(ZZ_pEX& x);  // prefix
void operator++(ZZ_pEX& x, int);  // postfix

ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator-=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator-=(ZZ_pEX& x, long a);

ZZ_pEX& operator--(ZZ_pEX& x);  // prefix
void operator--(ZZ_pEX& x, int);  // postfix

// procedural versions:

void add(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a + b
void sub(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a - b 
void negate(ZZ_pEX& x, const ZZ_pEX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZ_pEX operator*(const ZZ_pEX& a, const ZZ_pEX& b);

ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator*=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator*=(ZZ_pEX& x, long a);


// procedural versions:


void mul(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b); // x = a * b

void sqr(ZZ_pEX& x, const ZZ_pEX& a); // x = a^2
ZZ_pEX sqr(const ZZ_pEX& a);

// PROMOTIONS: *, mul promote {long,ZZ_p,ZZ_pE} to ZZ_pEX on (a, b).

void power(ZZ_pEX& x, const ZZ_pEX& a, long e);  // x = a^e (e >= 0)
ZZ_pEX power(const ZZ_pEX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ_pEX operator<<(const ZZ_pEX& a, long n);
ZZ_pEX operator>>(const ZZ_pEX& a, long n);

ZZ_pEX& operator<<=(ZZ_pEX& x, long n);
ZZ_pEX& operator>>=(ZZ_pEX& x, long n);

// procedural versions:

void LeftShift(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX LeftShift(const ZZ_pEX& a, long n);

void RightShift(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX RightShift(const ZZ_pEX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pE& b);
ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_p& b);
ZZ_pEX operator/(const ZZ_pEX& a, long b);

ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEX& b);

ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pE& a);
ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_p& a);
ZZ_pEX& operator/=(ZZ_pEX& x, long a);

ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEX& a);

// procedural versions:


void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b);
// q = a/b, r = a%b

void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pE& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_p& b);
void div(ZZ_pEX& q, const ZZ_pEX& a, long b);
// q = a/b

void rem(ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEX& b);
// r = a%b

long divide(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const ZZ_pEX& a, const ZZ_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when ZZ_pE is a field.

\**************************************************************************/


void GCD(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pEX GCD(const ZZ_pEX& a, const ZZ_pEX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(ZZ_pEX& d, ZZ_pEX& s, ZZ_pEX& t, const ZZ_pEX& a, const ZZ_pEX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < ZZ_pE::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo ZZ_pE::modulus(), 
and leading zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, ZZ_pEX& x);
ostream& operator<<(ostream& s, const ZZ_pEX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(ZZ_pEX& x, const ZZ_pEX& a); // x = derivative of a
ZZ_pEX diff(const ZZ_pEX& a);

void MakeMonic(ZZ_pEX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(ZZ_pEX& x, const ZZ_pEX& a, long hi);
ZZ_pEX reverse(const ZZ_pEX& a, long hi);

void reverse(ZZ_pEX& x, const ZZ_pEX& a);
ZZ_pEX reverse(const ZZ_pEX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_ZZ_pE& x, const ZZ_pEX& a, long n);
vec_ZZ_pE VectorCopy(const ZZ_pEX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(ZZ_pEX& x, long n);
ZZ_pEX random_ZZ_pEX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(ZZ_pEX& x, const vec_ZZ_pE& a);
ZZ_pEX BuildFromRoots(const vec_ZZ_pE& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(ZZ_pE& b, const ZZ_pEX& f, const ZZ_pE& a);
ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a);
// b = f(a)

void eval(ZZ_pE& b, const ZZ_pX& f, const ZZ_pE& a);
ZZ_pE eval(const ZZ_pEX& f, const ZZ_pE& a);
// b = f(a); uses ModComp algorithm for ZZ_pX

void eval(vec_ZZ_pE& b, const ZZ_pEX& f, const vec_ZZ_pE& a);
vec_ZZ_pE eval(const ZZ_pEX& f, const vec_ZZ_pE& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(ZZ_pEX& f, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
ZZ_pEX interpolate(const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(ZZ_pEX& x, const ZZ_pEX& a, long n); // x = a % X^n
ZZ_pEX trunc(const ZZ_pEX& a, long n);

void MulTrunc(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, long n);
ZZ_pEX MulTrunc(const ZZ_pEX& a, const ZZ_pEX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX SqrTrunc(const ZZ_pEX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
ZZ_pEX InvTrunc(ZZ_pEX& x, const ZZ_pEX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
ZZ_pEXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f);
ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEX& f);
// x = (a * b) % f

void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = a^2 % f

void MulByXMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX MulByXMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = (a * X) mod f

void InvMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pEX InvMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
ZZ_pEXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/ZZ_pEX.h>

void product(ZZ_pEX& x, const vec_ZZ_pEX& v, const ZZ_pEX& f)
{
   ZZ_pEXModulus F(f);
   ZZ_pEX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A ZZ_pEX may be used wherever a ZZ_pEXModulus is required,
and a ZZ_pEXModulus may be used wherever a ZZ_pEX is required.


\**************************************************************************/

class ZZ_pEXModulus {
public:
   ZZ_pEXModulus(); // initially in an unusable state

   ZZ_pEXModulus(const ZZ_pEX& f); // initialize with f, deg(f) > 0

   ZZ_pEXModulus(const ZZ_pEXModulus&); // copy

   ZZ_pEXModulus& operator=(const ZZ_pEXModulus&); // assignment

   ~ZZ_pEXModulus(); // destructor

   operator const ZZ_pEX& () const; // implicit read-only access to f

   const ZZ_pEX& val() const; // explicit read-only access to f
};

void build(ZZ_pEXModulus& F, const ZZ_pEX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration ZZ_pEXModulus F(f) is
// equivalent to ZZ_pEXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const ZZ_pEXModulus& F);  // return n=deg(f)

void MulMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEX& b,
            const ZZ_pEXModulus& F);
ZZ_pEX MulMod(const ZZ_pEX& a, const ZZ_pEX& b, const ZZ_pEXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pEX SqrMod(const ZZ_pEX& a, const ZZ_pEXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F);
ZZ_pEX PowerMod(const ZZ_pEX& a, const ZZ& e, const ZZ_pEXModulus& F);

void PowerMod(ZZ_pEX& x, const ZZ_pEX& a, long e, const ZZ_pEXModulus& F);
ZZ_pEX PowerMod(const ZZ_pEX& a, long e, const ZZ_pEXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(ZZ_pEX& x, const ZZ& e, const ZZ_pEXModulus& F);
ZZ_pEX PowerXMod(const ZZ& e, const ZZ_pEXModulus& F);

void PowerXMod(ZZ_pEX& x, long e, const ZZ_pEXModulus& F);
ZZ_pEX PowerXMod(long e, const ZZ_pEXModulus& F);

// x = X^e % f (e may be negative)

void rem(ZZ_pEX& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// x = a % f

void DivRem(ZZ_pEX& q, ZZ_pEX& r, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// q = a/f, r = a%f

void div(ZZ_pEX& q, const ZZ_pEX& a, const ZZ_pEXModulus& F);
// q = a/f

// operator notation:

ZZ_pEX operator/(const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pEX operator%(const ZZ_pEX& a, const ZZ_pEXModulus& F);

ZZ_pEX& operator/=(ZZ_pEX& x, const ZZ_pEXModulus& F);
ZZ_pEX& operator%=(ZZ_pEX& x, const ZZ_pEXModulus& F);



/**************************************************************************\

                             vectors of ZZ_pEX's

\**************************************************************************/


typedef Vec<ZZ_pEX> vec_ZZ_pEX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);
ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEX& h,
                    const ZZ_pEXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(ZZ_pEX& x1, ZZ_pEX& x2, const ZZ_pEX& g1, const ZZ_pEX& g2,
              const ZZ_pEX& h, const ZZ_pEXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(ZZ_pEX& x1, ZZ_pEX& x2, ZZ_pEX& x3,
              const ZZ_pEX& g1, const ZZ_pEX& g2, const ZZ_pEX& g3,
              const ZZ_pEX& h, const ZZ_pEXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a ZZ_pEXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct ZZ_pEXArgument {
   vec_ZZ_pEX H;
};

void build(ZZ_pEXArgument& H, const ZZ_pEX& h, const ZZ_pEXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(ZZ_pEX& x, const ZZ_pEX& g, const ZZ_pEXArgument& H,
             const ZZ_pEXModulus& F);

ZZ_pEX CompMod(const ZZ_pEX& g, const ZZ_pEXArgument& H,
                    const ZZ_pEXModulus& F);

extern thread_local long ZZ_pEXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// ZZ_pEXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in ZZ_pEXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(ZZ_pE& x, const ZZ_pEVector& a, const ZZ_pEX& b);
ZZ_pE project(const ZZ_pEVector& a, const ZZ_pEX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k,
                   const ZZ_pEX& h, const ZZ_pEXModulus& F);

vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k,
                   const ZZ_pEX& h, const ZZ_pEXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_ZZ_pE& x, const vec_ZZ_pE& a, long k,
                   const ZZ_pEXArgument& H, const ZZ_pEXModulus& F);

vec_ZZ_pE ProjectPowers(const vec_ZZ_pE& a, long k,
                   const ZZ_pEXArgument& H, const ZZ_pEXModulus& F);

// same as above, but uses a pre-computed ZZ_pEXArgument


class ZZ_pEXTransMultiplier { /* ... */ };

void build(ZZ_pEXTransMultiplier& B, const ZZ_pEX& b, const ZZ_pEXModulus& F);

void UpdateMap(vec_ZZ_pE& x, const vec_ZZ_pE& a,
               const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F);

vec_ZZ_pE UpdateMap(const vec_ZZ_pE& a,
               const ZZ_pEXMultiplier& B, const ZZ_pEXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Required: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when ZZ_pE is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(ZZ_pEX& h, const vec_ZZ_pE& a, long m);
ZZ_pEX MinPolySeq(const vec_ZZ_pE& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void ProbMinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX ProbMinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{ZZ_pE::degree()}.

void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void MinPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX MinPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);
ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void IrredPolyMod(ZZ_pEX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);
ZZ_pEX IrredPolyMod(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).

/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

The routines require that p is prime, but ZZ_pE need not be a field.

\**************************************************************************/


void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEXArgument& h,
             const ZZ_pEXModulus& F);

ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEXArgument& h,
             const ZZ_pEXModulus& F);

void CompTower(ZZ_pEX& x, const ZZ_pX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);

ZZ_pEX CompTower(const ZZ_pX& g, const ZZ_pEX& h,
             const ZZ_pEXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F,
                      long m);

ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void ProbMinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX ProbMinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over ZZ_p.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*ZZ_pE::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void MinPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX MinPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F, long m);

void IrredPolyTower(ZZ_pX& h, const ZZ_pEX& g, const ZZ_pEXModulus& F);

ZZ_pX IrredPolyTower(const ZZ_pEX& g, const ZZ_pEXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.


/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEXModulus& F);
ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& F);

void TraceMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pE TraceMod(const ZZ_pEX& a, const ZZ_pEXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_ZZ_pE& S, const ZZ_pEX& f);
vec_ZZ_pE TraceVec(const ZZ_pEX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& f);
ZZ_pE NormMod(const ZZ_pEX& a, const ZZ_pEX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(ZZ_pE& x, const ZZ_pEX& a, const ZZ_pEX& b);
ZZ_pE resultant(const ZZ_pEX& a, const ZZ_pEX& b);
// x = resultant(a, b)

// NormMod and resultant require that ZZ_pE is a field.




/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(ZZ_pEX& x) // x = 0
void set(ZZ_pEX& x); // x = 1

void ZZ_pEX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

ZZ_pEX::ZZ_pEX(INIT_SIZE_TYPE, long n);
// ZZ_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZ_pEX& zero();
// ZZ_pEX::zero() is a read-only reference to 0

void ZZ_pEX::swap(ZZ_pEX& x);
void swap(ZZ_pEX& x, ZZ_pEX& y);
// swap (via "pointer swapping")


ZZ_pEX::ZZ_pEX(long i, const ZZ_pE& c);
ZZ_pEX::ZZ_pEX(long i, const ZZ_p& c);
ZZ_pEX::ZZ_pEX(long i, long c);
// initialize to c*X^i, provided for backward compatibility
ntl-11.5.1/doc/ZZ_pEXFactoring.cpp.html0000644417616742025610000003124414064716023021352 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_pEXFactoring.cpp.html

/**************************************************************************\

MODULE: ZZ_pEXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over ZZ_pE, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/ZZ_pEX.h>
#include <NTL/pair_ZZ_pEX_long.h>

void SquareFreeDecomp(vec_pair_ZZ_pEX_long& u, const ZZ_pEX& f);
vec_pair_ZZ_pEX_long SquareFreeDecomp(const ZZ_pEX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_ZZ_pE& x, const ZZ_pEX& f);
vec_ZZ_pE FindRoots(const ZZ_pEX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(ZZ_pE& root, const ZZ_pEX& f);
ZZ_pE FindRoot(const ZZ_pEX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void NewDDF(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f,
            const ZZ_pEX& h, long verbose=0);

vec_pair_ZZ_pEX_long NewDDF(const ZZ_pEX& f, const ZZ_pEX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{ZZ_pE::cardinality()} mod f.  

// This routine implements the baby step/giant step algorithm
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form tmp-*.
// The definition of "large" is controlled by the variable

      extern thread_local double ZZ_pEXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds ZZ_pEXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).




void EDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, const ZZ_pEX& h,
         long d, long verbose=0);

vec_ZZ_pEX EDF(const ZZ_pEX& f, const ZZ_pEX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^{ZZ_pE::cardinality()} mod
// f.  d = degree of irreducible factors of f.  This routine
// implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0);
vec_ZZ_pEX RootEDF(const ZZ_pEX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_ZZ_pEX& factors, const ZZ_pEX& f, long verbose=0);
vec_ZZ_pEX SFCanZass(const ZZ_pEX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_ZZ_pEX_long& factors, const ZZ_pEX& f,
             long verbose=0);

vec_pair_ZZ_pEX_long CanZass(const ZZ_pEX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// ZZ_pEXArgBound (see ZZ_pEX.txt).



void mul(ZZ_pEX& f, const vec_pair_ZZ_pEX_long& v);
ZZ_pEX mul(const vec_pair_ZZ_pEX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const ZZ_pEX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// ZZ_pE::cardinality()^{-iter}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const ZZ_pEX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const ZZ_pEX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(ZZ_pEX& f, long n);
ZZ_pEX BuildIrred_ZZ_pEX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(ZZ_pEX& f, const ZZ_pEX& g);
ZZ_pEX BuildRandomIrred(const ZZ_pEX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.


long IterComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{ZZ_pE::cardinality()} mod f.  The common degree of the irreducible 
// factors of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const ZZ_pEX& h, const ZZ_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, 
// h = X^{ZZ_pE::cardinality()} mod f.  
// The common degree of the irreducible factors of f is
// computed Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(ZZ_pEX& w, const ZZ_pEX& a, long d, const ZZ_pEXModulus& F,
              const ZZ_pEX& h);

ZZ_pEX TraceMap(const ZZ_pEX& a, long d, const ZZ_pEXModulus& F,
              const ZZ_pEX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of ZZ_pE::cardinality().  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void PowerCompose(ZZ_pEX& w, const ZZ_pEX& h, long d, const ZZ_pEXModulus& F);

ZZ_pEX PowerCompose(const ZZ_pEX& h, long d, const ZZ_pEXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of ZZ_pE::cardinality().  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]

ntl-11.5.1/doc/ZZ_pX.cpp.html0000644417616742025610000016257714064716023017426 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_pX.cpp.html

/**************************************************************************\

MODULE: ZZ_pX

SUMMARY:

The class ZZ_pX implements polynomial arithmetic modulo p.

Polynomial arithmetic is implemented using the FFT, combined with the
Chinese Remainder Theorem.  A more detailed description of the
techniques used here can be found in [Shoup, J. Symbolic
Comp. 20:363-397, 1995].

Small degree polynomials are multiplied either with classical 
or Karatsuba algorithms.

\**************************************************************************/

#include <NTL/ZZ_p.h>
#include <NTL/vec_ZZ_p.h>

class ZZ_pX {
public:

   ZZ_pX(); // initialize to 0

   ZZ_pX(const ZZ_pX& a); // copy constructor
   explicit ZZ_pX(const ZZ_p& a); // promotion 
   explicit ZZ_pX(long a); // promotion 

   ZZ_pX& operator=(const ZZ_pX& a); // assignment
   ZZ_pX& operator=(const ZZ_p& a); // assignment
   ZZ_pX& operator=(const long a); // assignment

   ~ZZ_pX(); // destructor

   ZZ_pX(ZZ_pX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   ZZ_pX& operator=(ZZ_pX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   ZZ_pX(INIT_MONO_TYPE, long i, const ZZ_p& c);
   ZZ_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as ZZ_pX(INIT_MONO, i, c)

   ZZ_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to X^i, invoke as ZZ_pX(INIT_MONO, i)


   // typedefs to aid in generic programming
   typedef zz_p coeff_type;
   typedef zz_pE residue_type;
   typedef zz_pXModulus modulus_type;
   typedef zz_pXMultiplier multiplier_type;
   typedef fftRep fft_type;


   // ...


};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const ZZ_pX& a);  // return deg(a); deg(0) == -1.

const ZZ_p& coeff(const ZZ_pX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const ZZ_p& LeadCoeff(const ZZ_pX& a);
// returns leading term of a, or zero if a == 0

const ZZ_p& ConstTerm(const ZZ_pX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(ZZ_pX& x, long i, const ZZ_p& a);
void SetCoeff(ZZ_pX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(ZZ_pX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(ZZ_pX& x); // x is set to the monomial X

long IsX(const ZZ_pX& a); // test if x = X




ZZ_p& ZZ_pX::operator[](long i);
const ZZ_p& ZZ_pX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).


void ZZ_pX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void ZZ_pX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void ZZ_pX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const ZZ_pX& a, const ZZ_pX& b);
long operator!=(const ZZ_pX& a, const ZZ_pX& b);

// PROMOTIONS: operators ==, != promote {long, ZZ_p} to ZZ_pX on (a, b).

long IsZero(const ZZ_pX& a); // test for 0
long IsOne(const ZZ_pX& a); // test for 1


/**************************************************************************\

                                   Addition

\**************************************************************************/


// operator notation:

ZZ_pX operator+(const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX operator-(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX operator-(const ZZ_pX& a); // unary -

ZZ_pX& operator+=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator+=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator+=(ZZ_pX& x, long a);

ZZ_pX& operator-=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator-=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator-=(ZZ_pX& x, long a);

ZZ_pX& operator++(ZZ_pX& x);  // prefix
void operator++(ZZ_pX& x, int);  // postfix

ZZ_pX& operator--(ZZ_pX& x);  // prefix
void operator--(ZZ_pX& x, int);  // postfix

// procedural versions:


void add(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a + b
void sub(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a - b
void negate(ZZ_pX& x, const ZZ_pX& a); // x = -a


// PROMOTIONS: binary +, - and procedures add, sub promote
// {long, ZZ_p} to ZZ_pX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

ZZ_pX operator*(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX& operator*=(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX& operator*=(ZZ_pX& x, const ZZ_p& a);
ZZ_pX& operator*=(ZZ_pX& x, long a);

// procedural versions:

void mul(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b); // x = a * b

void sqr(ZZ_pX& x, const ZZ_pX& a); // x = a^2
ZZ_pX sqr(const ZZ_pX& a);

// PROMOTIONS: operator * and procedure mul promote {long, ZZ_p} to ZZ_pX
// on (a, b).

void power(ZZ_pX& x, const ZZ_pX& a, long e);  // x = a^e (e >= 0)
ZZ_pX power(const ZZ_pX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

ZZ_pX operator<<(const ZZ_pX& a, long n);
ZZ_pX operator>>(const ZZ_pX& a, long n);

ZZ_pX& operator<<=(ZZ_pX& x, long n);
ZZ_pX& operator>>=(ZZ_pX& x, long n);

// procedural versions:

void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX LeftShift(const ZZ_pX& a, long n);

void RightShift(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX RightShift(const ZZ_pX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

ZZ_pX operator/(const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX operator/(const ZZ_pX& a, const ZZ_p& b);
ZZ_pX operator/(const ZZ_pX& a, long b);


ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pX& b);
ZZ_pX& operator/=(ZZ_pX& x, const ZZ_p& b);
ZZ_pX& operator/=(ZZ_pX& x, long b);

ZZ_pX operator%(const ZZ_pX& a, const ZZ_pX& b);

ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pX& b);


// procedural versions:


void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b);
// q = a/b, r = a%b

void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b);
void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_p& b);
void div(ZZ_pX& q, const ZZ_pX& a, long b);
// q = a/b

void rem(ZZ_pX& r, const ZZ_pX& a, const ZZ_pX& b);
// r = a%b

long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const ZZ_pX& a, const ZZ_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when p is prime.

\**************************************************************************/


void GCD(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b);
ZZ_pX GCD(const ZZ_pX& a, const ZZ_pX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b);
// d = gcd(a,b), a s + b t = d 


// NOTE: A classical algorithm is used, switching over to a
// "half-GCD" algorithm for large degree


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be integers between 0 and p-1, and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary integers which are reduced modulo p, and leading zeros
stripped.

\**************************************************************************/

istream& operator>>(istream& s, ZZ_pX& x);
ostream& operator<<(ostream& s, const ZZ_pX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/

void diff(ZZ_pX& x, const ZZ_pX& a); // x = derivative of a
ZZ_pX diff(const ZZ_pX& a);

void MakeMonic(ZZ_pX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case.

void reverse(ZZ_pX& x, const ZZ_pX& a, long hi);
ZZ_pX reverse(const ZZ_pX& a, long hi);

void reverse(ZZ_pX& x, const ZZ_pX& a);
ZZ_pX reverse(const ZZ_pX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_ZZ_p& x, const ZZ_pX& a, long n);
vec_ZZ_p VectorCopy(const ZZ_pX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(ZZ_pX& x, long n);
ZZ_pX random_ZZ_pX(long n);
// generate a random polynomial of degree < n 



/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a);
ZZ_pX BuildFromRoots(const vec_ZZ_p& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a);
ZZ_p eval(const ZZ_pX& f, const ZZ_p& a);
// b = f(a)

void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a);
vec_ZZ_p eval(const ZZ_pX& f, const vec_ZZ_p& a);
//  b.SetLength(a.length()).  b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b);
ZZ_pX interpolate(const vec_ZZ_p& a, const vec_ZZ_p& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  p should
// be prime.

/**************************************************************************\

                       Arithmetic mod X^n

All routines require n >= 0, otherwise an error is raised.

\**************************************************************************/

void trunc(ZZ_pX& x, const ZZ_pX& a, long n); // x = a % X^n
ZZ_pX trunc(const ZZ_pX& a, long n);

void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n);
ZZ_pX MulTrunc(const ZZ_pX& a, const ZZ_pX& b, long n);
// x = a * b % X^n

void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX SqrTrunc(const ZZ_pX& a, long n);
// x = a^2 % X^n

void InvTrunc(ZZ_pX& x, const ZZ_pX& a, long n);
ZZ_pX InvTrunc(const ZZ_pX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
ZZ_pXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f);
ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pX& f);
// x = (a * b) % f

void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pX& f);
// x = a^2 % f

void MulByXMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX MulByXMod(const ZZ_pX& a, const ZZ_pX& f);
// x = (a * X) mod f
// NOTE: thread boosting enabled only if x does not alias a

void InvMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX InvMod(const ZZ_pX& a, const ZZ_pX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build a
ZZ_pXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

It is required that deg(f) > 0 and that LeadCoeff(f) is invertible.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include <NTL/ZZ_pX.h>

void product(ZZ_pX& x, const vec_ZZ_pX& v, const ZZ_pX& f)
{
   ZZ_pXModulus F(f);
   ZZ_pX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

Note that automatic conversions are provided so that a ZZ_pX can
be used wherever a ZZ_pXModulus is required, and a ZZ_pXModulus
can be used wherever a ZZ_pX is required.

\**************************************************************************/


class ZZ_pXModulus {
public:
   ZZ_pXModulus(); // initially in an unusable state

   ZZ_pXModulus(const ZZ_pXModulus&);  // copy

   ZZ_pXModulus& operator=(const ZZ_pXModulus&); // assignment

   ~ZZ_pXModulus();

   ZZ_pXModulus(const ZZ_pX& f); // initialize with f, deg(f) > 0

   operator const ZZ_pX& () const;
   // read-only access to f, implicit conversion operator

   const ZZ_pX& val() const;
   // read-only access to f, explicit notation

};

void build(ZZ_pXModulus& F, const ZZ_pX& f);
// pre-computes information about f and stores it in F.
// Note that the declaration ZZ_pXModulus F(f) is equivalent to
// ZZ_pXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const ZZ_pXModulus& F);  // return n=deg(f)

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F);
ZZ_pX MulMod(const ZZ_pX& a, const ZZ_pX& b, const ZZ_pXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_pX SqrMod(const ZZ_pX& a, const ZZ_pXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(ZZ_pX& x, const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F);
ZZ_pX PowerMod(const ZZ_pX& a, const ZZ& e, const ZZ_pXModulus& F);

void PowerMod(ZZ_pX& x, const ZZ_pX& a, long e, const ZZ_pXModulus& F);
ZZ_pX PowerMod(const ZZ_pX& a, long e, const ZZ_pXModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(ZZ_pX& x, const ZZ& e, const ZZ_pXModulus& F);
ZZ_pX PowerXMod(const ZZ& e, const ZZ_pXModulus& F);

void PowerXMod(ZZ_pX& x, long e, const ZZ_pXModulus& F);
ZZ_pX PowerXMod(long e, const ZZ_pXModulus& F);

// x = X^e % f (e may be negative)

void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, const ZZ& e,
                    const ZZ_pXModulus& F);

ZZ_pX PowerXPlusAMod(const ZZ_p& a, const ZZ& e,
                           const ZZ_pXModulus& F);

void PowerXPlusAMod(ZZ_pX& x, const ZZ_p& a, long e,
                    const ZZ_pXModulus& F);

ZZ_pX PowerXPlusAMod(const ZZ_p& a, long e,
                           const ZZ_pXModulus& F);

// x = (X + a)^e % f (e may be negative)


void rem(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXModulus& F);
// x = a % f

void DivRem(ZZ_pX& q, ZZ_pX& r, const ZZ_pX& a, const ZZ_pXModulus& F);
// q = a/f, r = a%f

void div(ZZ_pX& q, const ZZ_pX& a, const ZZ_pXModulus& F);
// q = a/f

// operator notation:

ZZ_pX operator/(const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_pX operator%(const ZZ_pX& a, const ZZ_pXModulus& F);

ZZ_pX& operator/=(ZZ_pX& x, const ZZ_pXModulus& F);
ZZ_pX& operator%=(ZZ_pX& x, const ZZ_pXModulus& F);



/**************************************************************************\


                                More Pre-Conditioning

If you need to compute a * b % f for a fixed b, but for many a's, it
is much more efficient to first build a ZZ_pXMultiplier B for b, and
then use the MulMod routine below.

Here is an example that multiplies each element of a vector by a fixed
polynomial modulo f.

#include <NTL/ZZ_pX.h>

void mul(vec_ZZ_pX& v, const ZZ_pX& b, const ZZ_pX& f)
{
   ZZ_pXModulus F(f);
   ZZ_pXMultiplier B(b, F);
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(v[i], v[i], B, F);
}

\**************************************************************************/


class ZZ_pXMultiplier {
public:
   ZZ_pXMultiplier(); // initially zero

   ZZ_pXMultiplier(const ZZ_pX& b, const ZZ_pXModulus& F);
      // initializes with b mod F, where deg(b) < deg(F)

   ZZ_pXMultiplier(const ZZ_pXMultiplier&);  // copy

   ZZ_pXMultiplier& operator=(const ZZ_pXMultiplier&);  // assignment

   ~ZZ_pXMultiplier();

   const ZZ_pX& val() const; // read-only access to b

};


void build(ZZ_pXMultiplier& B, const ZZ_pX& b, const ZZ_pXModulus& F);
// pre-computes information about b and stores it in B; deg(b) <
// deg(F)

void MulMod(ZZ_pX& x, const ZZ_pX& a, const ZZ_pXMultiplier& B,
                                      const ZZ_pXModulus& F);

// x = (a * b) % F; deg(a) < deg(F)

/**************************************************************************\

                             vectors of ZZ_pX's

\**************************************************************************/

typedef Vec<ZZ_pX> vec_ZZ_pX; // backward compatibility


/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F);
ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pX& h,
                    const ZZ_pXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2,
              const ZZ_pX& h, const ZZ_pXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.

void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3,
              const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3,
              const ZZ_pX& h, const ZZ_pXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a ZZ_pXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct ZZ_pXArgument {
   vec_ZZ_pX H;
};

void build(ZZ_pXArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& H,
             const ZZ_pXModulus& F);

ZZ_pX CompMod(const ZZ_pX& g, const ZZ_pXArgument& H,
                    const ZZ_pXModulus& F);

extern thread_local long ZZ_pXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// ZZ_pXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in ZZ_pXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(ZZ_p& x, const ZZ_pVector& a, const ZZ_pX& b);
ZZ_p project(const ZZ_pVector& a, const ZZ_pX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
                   const ZZ_pX& h, const ZZ_pXModulus& F);

vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k,
                   const ZZ_pX& h, const ZZ_pXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
                   const ZZ_pXArgument& H, const ZZ_pXModulus& F);

vec_ZZ_p ProjectPowers(const vec_ZZ_p& a, long k,
                   const ZZ_pXArgument& H, const ZZ_pXModulus& F);

// same as above, but uses a pre-computed ZZ_pXArgument


void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& a,
               const ZZ_pXMultiplier& B, const ZZ_pXModulus& F);

vec_ZZ_p UpdateMap(const vec_ZZ_p& a,
               const ZZ_pXMultiplier& B, const ZZ_pXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: must have a.length() <= deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output will always have high order zeroes stripped.





/**************************************************************************\

        Faster Composition and Projection with Pre-Conditioning

A new, experimental version of composition with preconditioning.
This interface was introduced in NTL v10.3.0, and it should be 
considered a preliminary interface and subject to change.

The class ZZ_pXNewArgument is similar to ZZ_pXArgument, but with
a different internal layout.  Copy constructor and assignment work.

Note that all NTL modular composition and power projection routines, 
as well as other routines that use modular composition power projection 
internally, now use this new class.

Note also that these routines do not pay any attention to the
ZZ_pXArgBound variable.

\**************************************************************************/

class ZZ_pXNewArgument {
 // ...
};

void build(ZZ_pXNewArgument& H, const ZZ_pX& h, const ZZ_pXModulus& F, long m);
// same functionality as the corresponding ZZ_pXArgument-based routine

void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXNewArgument& H,
             const ZZ_pXModulus& F);
// same functionality as the corresponding ZZ_pXArgument-based routine

void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
                   const ZZ_pXNewArgument& H, const ZZ_pXModulus& F);
// same functionality as the corresponding ZZ_pXArgument-based routine








/**************************************************************************\

                              Minimum Polynomials

These routines should be used with prime p.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m);
ZZ_pX MinPolySeq(const vec_ZZ_p& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX ProbMinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/p.

void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void MinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX MinPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m);
ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F, long m);

void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F);
ZZ_pX IrredPolyMod(const ZZ_pX& g, const ZZ_pXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                   Traces, norms, resultants

These routines should be used with prime p.

\**************************************************************************/


void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F);
ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& F);

void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_p TraceMod(const ZZ_pX& a, const ZZ_pXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_ZZ_p& S, const ZZ_pX& f);
vec_ZZ_p TraceVec(const ZZ_pX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f);
ZZ_p NormMod(const ZZ_pX& a, const ZZ_pX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& b);
ZZ_p resultant(const ZZ_pX& a, const ZZ_pX& b);
// x = resultant(a, b)

void CharPolyMod(ZZ_pX& g, const ZZ_pX& a, const ZZ_pX& f);
ZZ_pX CharPolyMod(const ZZ_pX& a, const ZZ_pX& f);
// g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) <
// deg(f);  this routine works for arbitrary f;  if f is irreducible,
// it is faster to use the IrredPolyMod routine, and then exponentiate
// if necessary (since in this case the CharPoly is just a power of
// the IrredPoly).


/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(ZZ_pX& x) // x = 0
void set(ZZ_pX& x); // x = 1

void ZZ_pX::kill();
// f.kill() sets f to 0 and frees all memory held by f; Equivalent to
// f.rep.kill().

ZZ_pX::ZZ_pX(INIT_SIZE_TYPE, long n);
// ZZ_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const ZZ_pX& ZZ_pX::zero();
// ZZ_pX::zero() is a read-only reference to 0

void swap(ZZ_pX& x, ZZ_pX& y);
// swap x and y (via "pointer swapping")

void ZZ_pX::swap(ZZ_pX& x);
// swap member function


ZZ_pX::ZZ_pX(long i, const ZZ_p& c);
ZZ_pX::ZZ_pX(long i, long c);
// initialize to c*X^i, provided for backward compatibility
ntl-11.5.1/doc/ZZ_pXFactoring.cpp.html0000644417616742025610000003232214064716023021243 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/ZZ_pXFactoring.cpp.html

/**************************************************************************\

MODULE: ZZ_pXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over ZZ_p, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/ZZ_pX.h>
#include <NTL/pair_ZZ_pX_long.h>

void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& f);
vec_pair_ZZ_pX_long SquareFreeDecomp(const ZZ_pX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a lest of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_ZZ_p& x, const ZZ_pX& f);
vec_ZZ_p FindRoots(const ZZ_pX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(ZZ_p& root, const ZZ_pX& f);
ZZ_p FindRoot(const ZZ_pX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX  SFBerlekamp(const ZZ_pX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].


void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f,
               long verbose=0);

vec_pair_ZZ_pX_long berlekamp(const ZZ_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, const ZZ_pX& h,
         long verbose=0);

vec_pair_ZZ_pX_long NewDDF(const ZZ_pX& f, const ZZ_pX& h,
         long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^p mod f.  

// This routine implements the baby step/giant step algorithm 
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form tmp-*.
// The definition of "large" is controlled by the variable

      extern thread_local double ZZ_pXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds ZZ_pXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).




void EDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& h,
         long d, long verbose=0);

vec_ZZ_pX EDF(const ZZ_pX& f, const ZZ_pX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^p mod f.  d =
// degree of irreducible factors of f.  This routine implements the
// algorithm of [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992].

void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX RootEDF(const ZZ_pX& f, long verbose=0);

// EDF for d==1

void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose=0);
vec_ZZ_pX SFCanZass(const ZZ_pX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f,
             long verbose=0);

vec_pair_ZZ_pX_long CanZass(const ZZ_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: In most situations, you should use the CanZass factoring
// routine, rather than Berlekamp: it is faster and uses less space.

void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v);
ZZ_pX mul(const vec_pair_ZZ_pX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const ZZ_pX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// p^{-iter}.  This implements an algorithm from [Shoup, J. Symbolic
// Comp. 17:371-391, 1994].

long DetIrredTest(const ZZ_pX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const ZZ_pX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(ZZ_pX& f, long n);
ZZ_pX BuildIrred_ZZ_pX(long n);

// Build a monic irreducible poly of degree n.

void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g);
ZZ_pX BuildRandomIrred(const ZZ_pX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F);

// f is assumed to be an "equal degree" polynomial; h = X^p mod f.
// The common degree of the irreducible factors of f is computed This
// routine is useful in counting points on elliptic curves

long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F);

// Same as above, but uses a slightly faster probabilistic algorithm.
// The return value may be 0 or may be too big, but for large p
// (relative to n), this happens with very low probability.

void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F,
              const ZZ_pX& h);

ZZ_pX TraceMap(const ZZ_pX& a, long d, const ZZ_pXModulus& F,
              const ZZ_pX& h);

// w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h =
// X^q mod f, q a power of p.  This routine implements an algorithm
// from [von zur Gathen and Shoup, Computational Complexity 2:187-224,
// 1992].

void PowerCompose(ZZ_pX& w, const ZZ_pX& h, long d, const ZZ_pXModulus& F);

ZZ_pX PowerCompose(const ZZ_pX& h, long d, const ZZ_pXModulus& F);

// w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q
// a power of p.  This routine implements an algorithm from [von zur
// Gathen and Shoup, Computational Complexity 2:187-224, 1992]

ntl-11.5.1/doc/lzz_p.cpp.html0000644417616742025610000005376614064716023017551 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_p.cpp.html


/**************************************************************************\

MODULE: zz_p

SUMMARY:

The class zz_p is used to represent integers mod p, where 1 <= p <
NTL_SP_BOUND.  Note that NTL_SP_BOUND is usually 2^30 on 32-bit machines and
2^50 on 64-bit machines.

The modulus p may be any positive integer, not necessarily prime.

Objects of the class zz_p are represented as a long in the range 0..p-1.

An executing program maintains a "current modulus", which is set to p using
zz_p::init(p).  The current modulus *must* be initialized before any operations
on zz_p's are performed.  The modulus may be changed, and a mechanism is provided
for saving and restoring a modulus (see classes zz_pPush and zz_pContext below).

\**************************************************************************/

#include <NTL/ZZ.h>
#include <NTL/FFT.h>
#include <NTL/SmartPtr.h>


class zz_p {
public:

   zz_p(); // initial value 0

   zz_p(const zz_p& a); // copy constructor
   explicit zz_p(long a); // promotion constructor

   zz_p& operator=(const zz_p& a); // assignment
   zz_p& operator=(long a); // assignment

   static void init(long p);
   // set the modulus to p, where p > 1.  This must be called before any
   // zz_p constructors are invoked.
   // The number p must have at most NTL_SP_NBITS bits.

   static long modulus();
   // zz_p::modulus() yields read-only reference to the current
   // modulus


   // typedefs to aid in generic programming
   typedef long rep_type;
   typedef zz_pContext context_type;
   typedef zz_pBak bak_type;
   typedef zz_pPush push_type;
   typedef zz_pX poly_type;

};


long rep(zz_p a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(zz_p a, zz_p b);
long operator!=(zz_p a, zz_p b);

long IsZero(zz_p a);  // test for 0
long IsOne(zz_p a);  // test for 1

// PROMOTIONS: operators ==, != promote long to zz_p on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

zz_p operator+(zz_p a, zz_p b);
zz_p operator-(zz_p a, zz_p b);

zz_p operator-(zz_p a); // unary -

zz_p& operator+=(zz_p& x, zz_p a);
zz_p& operator+=(zz_p& x, long a);

zz_p& operator-=(zz_p& x, zz_p a);
zz_p& operator-=(zz_p& x, long a);

zz_p& operator++(zz_p& x);  // prefix
void operator++(zz_p& x, int);  // postfix

zz_p& operator--(zz_p& x);  // prefix
void operator--(zz_p& x, int);  // postfix

// procedural versions:


void add(zz_p& x, zz_p a, zz_p b); // x = a + b
void sub(zz_p& x, zz_p a, zz_p b); // x = a - b 
void negate(zz_p& x, zz_p a); // x = -a

// PROMOTIONS: binary +, -, and procedures add, sub promote
// from long to zz_p on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/

// operator notation:

zz_p operator*(zz_p a, zz_p b);

zz_p& operator*=(zz_p& x, zz_p a);
zz_p& operator*=(zz_p& x, long a);

// procedural versions:

void mul(zz_p& x, zz_p a, zz_p b); // x = a * b

void sqr(zz_p& x, zz_p a); // x = a^2
zz_p sqr(zz_p a);

// PROMOTIONS: operator * and procedure mul promote from long to zz_p
// on (a, b).


/**************************************************************************\

                                  Division

\**************************************************************************/

operator notation:

zz_p operator/(z_p a, zz_p b);

zz_p& operator/=(zz_p& x, zz_p a);
zz_p& operator/=(zz_p& x, long a);

procedural versions:

void div(zz_p& x, zz_p a, zz_p b);
// x = a/b

void inv(zz_p& x, zz_p a);
zz_p inv(zz_p a);
// x = 1/a

// PROMOTIONS: operator / and procedure div promote from long to zz_p
// on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/


void power(zz_p& x, zz_p a, long e); // x = a^e (e may be negative)
zz_p power(zz_p a, long e);


/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(zz_p& x);
zz_p random_zz_p();
// x = random element in zz_p.  Uses RandomBnd from ZZ.

void VectorRandom(long k, zz_p *x);
// equivalent to random(x[i]) for i in [0..k), but fatser


/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, zz_p a);

istream& operator>>(istream& s, zz_p& x);
// a ZZ is read and reduced mod p

/**************************************************************************\

                       Modulus Switching 

A class zz_pPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to p, and automatically restore it:

   { 
      zz_pPush push(p); 

      ...

   }

The constructor for push will save the current modulus, and install p as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      zz_pPush push; // just backup current modulus

        ...

      zz_p::init(p1); // install p1 

        ...

      zz_p::init(p2); // install p2

      // reinstall original modulus as close of scope
   }

      
The zz_pPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see zz_pContext below.  There is also an older zz_pBak class
that may also be useful.

..........................................................................

It is critical that zz_p objects created under one zz_p modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
zz_p modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any zz_p object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.

\**************************************************************************/


// A convenient interface for common cases:

class zz_pPush {
public:

zz_pPush();  // just backup current modulus

explicit zz_pPush(long p, long maxroot=NTL_FFTMaxRoot);
zz_pPush(INIT_FFT_TYPE, long index);
zz_pPush(INIT_USER_FFT_TYPE, long p);
explicit zz_pPush(const zz_pContext& context);
  // backup current modulus and install the given one
  // see documentation for zz_p::init for more details

private:
zz_pPush(const zz_pPush&); // disabled
void operator=(const zz_pPush&); // disabled

};



// more general context switching:
// A zz_pContext object has a modulus q (possibly "null")

class zz_pContext {


public:

zz_pContext();  // q = "null"

explicit zz_pContext(long p);
zz_pContext(INIT_FFT_TYPE, long index);
zz_pContext(INIT_USER_FFT_TYPE, long p);
  // q = the given modulus
  // see documentation for zz_p::init for more details


void save(); // q = CurrentModulus
void restore() const; // CurrentModulus = q

zz_pContext(const zz_pContext&);  // copy
zz_pContext& operator=(const zz_pContext&); // assignment
~zz_pContext(); // destructor


};


/ An older interface:
// To describe this logic, think of a zz_pBak object
// of having two components: a modulus q (possibly "null") and 
// an "auto-restore bit" b.

class zz_pBak {
public:


   zz_pBak();  // q = "null", b = 0

   ~zz_pBak();  // if (b) CurrentModulus = q

   void save();  // q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = q, b = 0


private:
   zz_pBak(const zz_pBak&);  // copy disabled
   void operator=(const zz_pBak&);  // assignment disabled
};








/**************************************************************************\

                               Miscellany

\**************************************************************************/


void clear(zz_p& x); // x = 0
void set(zz_p& x); // x = 1

static mulmod_t zz_p::ModulusInverse();
// zz_p::ModulusInverse() returns PrepMulMod(zz_p::modulus()) 

static zz_p zz_p::zero();
// zz_p::zero() yields a read-only reference to zero

void swap(zz_p& x, zz_p& y);
// swap x and y 

static void zz_p::init(long p, long maxroot);
// Same as ordinary zz_p::init(p), but somewhat more efficient.  If you are
// going to perform arithmetic modulo a degree n polynomial, in which
// case set maxroot to NextPowerOfTwo(n)+1.  This is useful, for
// example, if you are going to factor a polynomial of degree n modulo
// p, and you know n in advance.
// If maxroot is set too low, the program will abort with an
// appropriate error message.

static void zz_p::FFTInit(long i);
// sets modulus to the i-th FFT prime (counting from 0).  FFT primes
// are NTL_SP_NBITS-bit primes p, where p-1 is divisible by a high power
// of two.  Thus, polynomial arithmetic mod p can be implemented
// particularly efficiently using the FFT.  As i increases, the power
// of 2 that divides p-1 gets smaller, thus placing a more severe
// restriction on the degrees of the polynomials to be multiplied.

static void zz_p::UserFFTInit(long p);
// set the modulus to a user-provided FFT prime p. To be useful,
// p-1 should be divisibly by a high power of 2. 
// The function is a utility routine that may be used to 
// calculate this value (see below). 
// If you are going to perform arithmetic modulo a degree n polynomial, 
// you will want CalcMaxRoot(p) >= NextPowerOfTwo(n)+1. 

zz_pContext::zz_pContext(long p, long maxroot);
// constructor for a zz_pContext with same semantics
// as zz_p::init(p, maxroot) above.

zz_pContext::zz_pContext(INIT_FFT_TYPE, long i);
// constructor for a zz_pContext with same semantics
// as zz_p::FFTInit(i) above; invoke as zz_pContext(INIT_FFT, i).

zz_pContext::zz_pContext(INIT_USER_FFT_TYPE, long p);
// constructor for a zz_pContext with same semantics
// as zz_p::UserFFTInit(p) above; invoke as zz_pContext(INIT_USER_FFT, p).

zz_p::zz_p(INIT_NO_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

zz_p::zz_p(INIT_ALLOC_TYPE);
// provided for consistency with other classes, initialize to zero

zz_p::allocate();
// provided for consistency with other classes, no action

long CalcMaxRoot(long p);
// p is assumed to be an odd prime.
// Returns the largest k such that 2^k divides p-1
// and such that k does not exceed an implementation defined
// constant.  This represents the max power of two for which
// an FFT mod p is supported.

void VectorConv(long k, zz_p *x, const ZZ *a);
void VectorConv(long k, zz_p *x, const long *a);
// equivalent to conv(x[i], a[i]) for i in [0..k), but fatser





ntl-11.5.1/doc/lzz_pE.cpp.html0000644417616742025610000005321314064716023017641 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_pE.cpp.html


/**************************************************************************\

MODULE: zz_pE

SUMMARY:

The class zz_pE is used to represent polynomials in Z_p[X] modulo a
polynomial P.  The modulus P may be any polynomial with deg(P) > 0,
not necessarily irreducible.  The modulus p defining Z_p need
not be prime either.

Objects of the class zz_pE are represented as a zz_pX of degree < deg(P).

An executing program maintains a "current modulus", which is set to P
using zz_pE::init(P).  The current modulus for zz_pE (as well as for zz_p)
*must* be initialized before an operations on zz_pE's are performed.

The modulus may be changed, and a mechanism is provided for saving and
restoring a modulus (see classes zz_pEPush and zz_pEContext below).

\**************************************************************************/

#include <NTL/lzz_pX.h>

class zz_pE {
public:

   zz_pE(); // initial value 0

   zz_pE(const zz_pE& a); // copy constructor
   explicit zz_pE(const zz_p& a); // promotion 
   explicit zz_pE(long a); // promotion 

   zz_pE& operator=(const zz_pE& a); // assignment
   zz_pE& operator=(const zz_p& a); // assignment
   zz_pE& operator=(long a); // assignment

   ~zz_pE(); // destructor

   zz_pE(zz_pE&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   zz_pE& operator=(zz_pE&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif

   static void init(const zz_pX& P);
   // zz_pE::init(P) initializes the current modulus to P;
   // required: deg(P) >= 1.

   static const zz_pXModulus& modulus();
   // zz_pE::modulus() yields read-only reference to the current modulus 

   static long degree();
   // zz_pE::degree() returns deg(P)

   // typedefs to aid generic programming
   typedef zz_pX rep_type;
   typedef zz_pEContext context_type;
   typedef zz_pEBak bak_type;
   typedef zz_pEPush push_type;
   typedef zz_pEX poly_type;

};


const zz_pX& rep(const zz_pE& a); // read-only access to representation of a



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long operator==(const zz_pE& a, const zz_pE& b);
long operator!=(const zz_pE& a, const zz_pE& b);

long IsZero(const zz_pE& a);  // test for 0
long IsOne(const zz_pE& a);  // test for 1

// PROMOTIONS: ==, != promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                    Addition 

\**************************************************************************/

// operator notation:

zz_pE operator+(const zz_pE& a, const zz_pE& b);

zz_pE operator-(const zz_pE& a, const zz_pE& b);
zz_pE operator-(const zz_pE& a);

zz_pE& operator+=(zz_pE& x, const zz_pE& a);
zz_pE& operator+=(zz_pE& x, const zz_p& a);
zz_pE& operator+=(zz_pE& x, long a);

zz_pE& operator++(zz_pE& x); // prefix
void operator++(zz_pE& x, int); // postfix

zz_pE& operator-=(zz_pE& x, const zz_pE& a);
zz_pE& operator-=(zz_pE& x, const zz_p& a);
zz_pE& operator-=(zz_pE& x, long a);

zz_pE& operator--(zz_pE& x); // prefix
void operator--(zz_pE& x, int); // postfix

// procedural versions:

void add(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a + b
void sub(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a - b 
void negate(zz_pE& x, const zz_pE& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                  Multiplication 

\**************************************************************************/


// operator notation:

zz_pE operator*(const zz_pE& a, const zz_pE& b);

zz_pE& operator*=(zz_pE& x, const zz_pE& a);
zz_pE& operator*=(zz_pE& x, const zz_p& a);
zz_pE& operator*=(zz_pE& x, long a);

// procedural versions:


void mul(zz_pE& x, const zz_pE& a, const zz_pE& b); // x = a * b

void sqr(zz_pE& x, const zz_pE& a); // x = a^2
zz_pE sqr(const zz_pE& a);

// PROMOTIONS: *, mul promote {long, zz_p} to zz_pE on (a, b).



/**************************************************************************\

                                     Division

\**************************************************************************/


// operator notation:

zz_pE operator/(const zz_pE& a, const zz_pE& b);

zz_pE& operator/=(zz_pE& x, const zz_pE& a);
zz_pE& operator/=(zz_pE& x, const zz_p& a);
zz_pE& operator/=(zz_pE& x, long a);


// procedural versions:

void div(zz_pE& x, const zz_pE& a, const zz_pE& b);
// x = a/b.  If b is not invertible, an error is raised.

void inv(zz_pE& x, const zz_pE& a);
zz_pE inv(const zz_pE& a);
// x = 1/a

PROMOTIONS: /, div promote {long, zz_p} to zz_pE on (a, b).


/**************************************************************************\

                                  Exponentiation

\**************************************************************************/



void power(zz_pE& x, const zz_pE& a, const ZZ& e);
zz_pE power(const zz_pE& a, const ZZ& e);

void power(zz_pE& x, const zz_pE& a, long e);
zz_pE power(const zz_pE& a, long e);

// x = a^e (e may be negative)



/**************************************************************************\

                               Random Elements

\**************************************************************************/


void random(zz_pE& x);
zz_pE random_zz_pE();
// x = random element in zz_pE.

/**************************************************************************\

                               Norms and Traces

\**************************************************************************/



void trace(zz_p& x, const zz_pE& a);  // x = trace of a
zz_p trace(const zz_pE& a);

void norm(zz_p& x, const zz_pE& a);   // x = norm of a
zz_p norm(const zz_pE& a);



/**************************************************************************\

                                Input/Output

\**************************************************************************/


ostream& operator<<(ostream& s, const zz_pE& a);

istream& operator>>(istream& s, zz_pE& x);
// a zz_pX is read and reduced mod p


/**************************************************************************\

                       Modulus Switching 

A class zz_pEPush is provided for "backing up" the current modulus
and installing a new one.

Here is what you do to save the current modulus, temporarily
set it to P, and automatically restore it:

   { 
      zz_pEPush push(P); 

      ...

   }

The constructor for push will save the current modulus, and install P as the
current modulus.  The destructor for push will restore the old modulus when the
scope enclosing it exits.  This is the so-called RAII (resource acquisition is
initialization) paradigm.

You could also do the following:

   {
      zz_pEPush push; // just backup current modulus

        ...

      zz_pE::init(P1); // install P1 

        ...

      zz_pE::init(P2); // install P2

      // reinstall original modulus as close of scope
   }

      
The zz_pEPush interface is good for implementing simple stack-like
modulus "context switching".  For more general context switching,
see zz_pEContext below.  There is also an older zz_pEBak class
that may also be useful.

..........................................................................

It is critical that zz_pE objects created under one zz_pE modulus are not used in
any non-trivial way "out of context", i.e., under a different (or undefined)
zz_pE modulus.  However, for ease-of-use, some operations may be safely
performed out of context.  These safe operations include: the default and copy
constructor, the destructor, and the assignment operator.  In addition is is
generally safe to read any zz_pE object out of context (i.e., printing it out, or
fetching its underlying representive using the rep() function).

Any unsafe uses out of context are not in general checked, and may 
lead to unpredictable behavior.


\**************************************************************************/


// A convenient interface for common cases

class zz_pEPush {

public:
zz_pEPush();  // backup current modulus
explicit zz_pEPush(const zz_pX& p);
explicit zz_pEPush(const zz_pEContext& context);
  // backup current modulus and install the given one

private:
zz_pEPush(const zz_pEPush&); // disabled
void operator=(const zz_pEPush&); // disabled

};



// more general context switching:
// A zz_pEContext object has a modulus Q (possibly "null"),

class zz_pEContext {


public:

zz_pEContext(); // Q = "null"
explicit zz_pEContext(const zz_pX& P); // Q = P

void save(); // Q = CurrentModulus
void restore() const; // CurrentModulus = Q

zz_pEContext(const zz_pEContext&);  // copy
zz_pEContext& operator=(const zz_pEContext&); // assignment
~zz_pEContext(); // destructor


};


// An older interface:
// To describe this logic, think of a zz_pEBak object
// of having two components: a modulus Q (possibly "null") and 
// an "auto-restore bit" b.


class zz_pEBak {
public:


   zz_pEBak();  // Q = "null", b = 0

   ~zz_pEBak();  // if (b) CurrentModulus = Q

   void save();  // Q = CurrentModulus, b = 1 
   void restore();  // CurrentModulus = Q, b = 0


private:
   zz_pEBak(const zz_pEBak&);  // copy disabled
   void operator=(const zz_pEBak&);  // assignment disabled
};






/**************************************************************************\

                               Miscellany

\**************************************************************************/

void clear(zz_pE& x); // x = 0
void set(zz_pE& x); // x = 1

static const zz_pE& zz_pE::zero();
// zz_pE::zero() yields a read-only reference to zero

void zz_pE::swap(zz_pE& x);
void swap(zz_pE& x, zz_pE& y);
// swap (done by "pointer swapping", if possible).

static ZZ& zz_pE::cardinality();
// yields the cardinality, i.e., p^{zz_pE::degree()}

zz_pE::zz_pE(INIT_NO_ALLOC_TYPE);
// special constructor: invoke as zz_pE x(INIT_NO_ALLOC);
// initializes x to 0, but allocates no space (this is now the default)

zz_pE::zz_pE(INIT_ALLOC_TYPE);
// special constructor: invoke as zz_pE x(INIT_ALLOC);
// initializes x to 0, but allocates space

zz_pE::allocate();
// useful in conjunction with the INIT_NO_ALLLOC constructor:
// x.allocate() will pre-allocate space for x, using the
// current modulus

ntl-11.5.1/doc/lzz_pEX.cpp.html0000644417616742025610000016021714064716023017774 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_pEX.cpp.html

/**************************************************************************\

MODULE: zz_pEX

SUMMARY:

The class zz_pEX represents polynomials over zz_pE,
and so can be used, for example, for arithmentic in GF(p^n)[X].
However, except where mathematically necessary (e.g., GCD computations),
zz_pE need not be a field.

\**************************************************************************/

#include <NTL/lzz_pE.h>
#include <NTL/vec_lzz_pE.h>

class zz_pEX {
public:

   zz_pEX(); // initial value 0

   zz_pEX(const zz_pEX& a); // copy
   zz_pEX(const zz_pE& a); // promotion
   zz_pEX(const zz_p& a);
   zz_pEX(long a);

   zz_pEX& operator=(const zz_pEX& a); // assignment
   zz_pEX& operator=(const zz_pE& a);
   zz_pEX& operator=(const zz_p& a);
   zz_pEX& operator=(long a);

   ~zz_pEX(); // destructor


   zz_pEX(zz_pEX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   zz_pEX& operator=(zz_pEX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif


   zz_pEX(INIT_MONO_TYPE, long i, const zz_pE& c);
   zz_pEX(INIT_MONO_TYPE, long i, const zz_p& c);
   zz_pEX(INIT_MONO_TYPE, long i, long c);
   // initilaize to c*X^i; invoke as zz_pEX(INIT_MONO, i, c)

   zz_pEX(INIT_MONO_TYPE, long i);
   // initilaize to X^i; invoke as zz_pEX(INIT_MONO, i)

   // typedefs to aid in generic programming
   typedef zz_pE coeff_type;
   typedef zz_pEXModulus modulus_type;

   // ...


};



/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().

NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const zz_pEX& a);  // return deg(a); deg(0) == -1.

const zz_pE& coeff(const zz_pEX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const zz_pE& LeadCoeff(const zz_pEX& a);
// returns leading term of a, or zero if a == 0

const zz_pE& ConstTerm(const zz_pEX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(zz_pEX& x, long i, const zz_pE& a);
void SetCoeff(zz_pEX& x, long i, const zz_p& a);
void SetCoeff(zz_pEX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(zz_pEX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(zz_pEX& x); // x is set to the monomial X

long IsX(const zz_pEX& a); // test if x = X




zz_pE& zz_pEX::operator[](long i);
const zz_pE& zz_pEX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void zz_pEX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void zz_pEX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void zz_pEX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const zz_pEX& a, const zz_pEX& b);
long operator!=(const zz_pEX& a, const zz_pEX& b);

long IsZero(const zz_pEX& a); // test for 0
long IsOne(const zz_pEX& a); // test for 1

// PROMOTIONS: ==, != promote {long,zz_p,zz_pE} to zz_pEX on (a, b).

/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

zz_pEX operator+(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator-(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator-(const zz_pEX& a);

zz_pEX& operator+=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator+=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator+=(zz_pEX& x, const zz_p& a);
zz_pEX& operator+=(zz_pEX& x, long a);


zz_pEX& operator++(zz_pEX& x);  // prefix
void operator++(zz_pEX& x, int);  // postfix

zz_pEX& operator-=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator-=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator-=(zz_pEX& x, const zz_p& a);
zz_pEX& operator-=(zz_pEX& x, long a);

zz_pEX& operator--(zz_pEX& x);  // prefix
void operator--(zz_pEX& x, int);  // postfix

// procedural versions:

void add(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a + b
void sub(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a - b 
void negate(zz_pEX& x, const zz_pEX& a); // x = - a 

// PROMOTIONS: +, -, add, sub promote {long,zz_p,zz_pE} to zz_pEX on (a, b).



/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

zz_pEX operator*(const zz_pEX& a, const zz_pEX& b);

zz_pEX& operator*=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator*=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator*=(zz_pEX& x, const zz_p& a);
zz_pEX& operator*=(zz_pEX& x, long a);


// procedural versions:


void mul(zz_pEX& x, const zz_pEX& a, const zz_pEX& b); // x = a * b

void sqr(zz_pEX& x, const zz_pEX& a); // x = a^2
zz_pEX sqr(const zz_pEX& a);

// PROMOTIONS: *, mul promote {long,zz_p,zz_pE} to zz_pEX on (a, b).

void power(zz_pEX& x, const zz_pEX& a, long e);  // x = a^e (e >= 0)
zz_pEX power(const zz_pEX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

zz_pEX operator<<(const zz_pEX& a, long n);
zz_pEX operator>>(const zz_pEX& a, long n);

zz_pEX& operator<<=(zz_pEX& x, long n);
zz_pEX& operator>>=(zz_pEX& x, long n);

// procedural versions:

void LeftShift(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX LeftShift(const zz_pEX& a, long n);

void RightShift(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX RightShift(const zz_pEX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

zz_pEX operator/(const zz_pEX& a, const zz_pEX& b);
zz_pEX operator/(const zz_pEX& a, const zz_pE& b);
zz_pEX operator/(const zz_pEX& a, const zz_p& b);
zz_pEX operator/(const zz_pEX& a, long b);

zz_pEX operator%(const zz_pEX& a, const zz_pEX& b);

zz_pEX& operator/=(zz_pEX& x, const zz_pEX& a);
zz_pEX& operator/=(zz_pEX& x, const zz_pE& a);
zz_pEX& operator/=(zz_pEX& x, const zz_p& a);
zz_pEX& operator/=(zz_pEX& x, long a);

zz_pEX& operator%=(zz_pEX& x, const zz_pEX& a);

// procedural versions:


void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEX& b);
// q = a/b, r = a%b

void div(zz_pEX& q, const zz_pEX& a, const zz_pEX& b);
void div(zz_pEX& q, const zz_pEX& a, const zz_pE& b);
void div(zz_pEX& q, const zz_pEX& a, const zz_p& b);
void div(zz_pEX& q, const zz_pEX& a, long b);
// q = a/b

void rem(zz_pEX& r, const zz_pEX& a, const zz_pEX& b);
// r = a%b

long divide(zz_pEX& q, const zz_pEX& a, const zz_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const zz_pEX& a, const zz_pEX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0


/**************************************************************************\

                                   GCD's

These routines are intended for use when zz_pE is a field.

\**************************************************************************/


void GCD(zz_pEX& x, const zz_pEX& a, const zz_pEX& b);
zz_pEX GCD(const zz_pEX& a, const zz_pEX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(zz_pEX& d, zz_pEX& s, zz_pEX& t, const zz_pEX& a, const zz_pEX& b);
// d = gcd(a,b), a s + b t = d 


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be polynomials of degree < zz_pE::degree() and
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary polynomials which are reduced modulo zz_pE::modulus(), 
and leading zeros stripped.

\**************************************************************************/

istream& operator>>(istream& s, zz_pEX& x);
ostream& operator<<(ostream& s, const zz_pEX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(zz_pEX& x, const zz_pEX& a); // x = derivative of a
zz_pEX diff(const zz_pEX& a);

void MakeMonic(zz_pEX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case

void reverse(zz_pEX& x, const zz_pEX& a, long hi);
zz_pEX reverse(const zz_pEX& a, long hi);

void reverse(zz_pEX& x, const zz_pEX& a);
zz_pEX reverse(const zz_pEX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_zz_pE& x, const zz_pEX& a, long n);
vec_zz_pE VectorCopy(const zz_pEX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.




/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(zz_pEX& x, long n);
zz_pEX random_zz_pEX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(zz_pEX& x, const vec_zz_pE& a);
zz_pEX BuildFromRoots(const vec_zz_pE& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n = a.length()

void eval(zz_pE& b, const zz_pEX& f, const zz_pE& a);
zz_pE eval(const zz_pEX& f, const zz_pE& a);
// b = f(a)

void eval(zz_pE& b, const zz_pX& f, const zz_pE& a);
zz_pE eval(const zz_pEX& f, const zz_pE& a);
// b = f(a); uses ModComp algorithm for zz_pX

void eval(vec_zz_pE& b, const zz_pEX& f, const vec_zz_pE& a);
vec_zz_pE eval(const zz_pEX& f, const vec_zz_pE& a);
//  b.SetLength(a.length()); b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(zz_pEX& f, const vec_zz_pE& a, const vec_zz_pE& b);
zz_pEX interpolate(const vec_zz_pE& a, const vec_zz_pE& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  

/**************************************************************************\

                       Arithmetic mod X^n

Required: n >= 0; otherwise, an error is raised.

\**************************************************************************/

void trunc(zz_pEX& x, const zz_pEX& a, long n); // x = a % X^n
zz_pEX trunc(const zz_pEX& a, long n);

void MulTrunc(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, long n);
zz_pEX MulTrunc(const zz_pEX& a, const zz_pEX& b, long n);
// x = a * b % X^n

void SqrTrunc(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX SqrTrunc(const zz_pEX& a, long n);
// x = a^2 % X^n

void InvTrunc(zz_pEX& x, const zz_pEX& a, long n);
zz_pEX InvTrunc(zz_pEX& x, const zz_pEX& a, long n);
// computes x = a^{-1} % X^m.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.


NOTE: if you want to do many computations with a fixed f, use the
zz_pEXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b, const zz_pEX& f);
zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEX& f);
// x = (a * b) % f

void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX SqrMod(const zz_pEX& a, const zz_pEX& f);
// x = a^2 % f

void MulByXMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX MulByXMod(const zz_pEX& a, const zz_pEX& f);
// x = (a * X) mod f

void InvMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
zz_pEX InvMod(const zz_pEX& a, const zz_pEX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(zz_pEX& x, const zz_pEX& a, const zz_pEX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
zz_pEXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations.

As an example, the following routine the product modulo f of a vector
of polynomials.

#include <NTL/lzz_pEX.h>

void product(zz_pEX& x, const vec_zz_pEX& v, const zz_pEX& f)
{
   zz_pEXModulus F(f);
   zz_pEX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}

NOTE: A zz_pEX may be used wherever a zz_pEXModulus is required,
and a zz_pEXModulus may be used wherever a zz_pEX is required.


\**************************************************************************/

class zz_pEXModulus {
public:
   zz_pEXModulus(); // initially in an unusable state

   zz_pEXModulus(const zz_pEX& f); // initialize with f, deg(f) > 0

   zz_pEXModulus(const zz_pEXModulus&); // copy

   zz_pEXModulus& operator=(const zz_pEXModulus&); // assignment

   ~zz_pEXModulus(); // destructor

   operator const zz_pEX& () const; // implicit read-only access to f

   const zz_pEX& val() const; // explicit read-only access to f
};

void build(zz_pEXModulus& F, const zz_pEX& f);
// pre-computes information about f and stores it in F.  Must have
// deg(f) > 0.  Note that the declaration zz_pEXModulus F(f) is
// equivalent to zz_pEXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).


long deg(const zz_pEXModulus& F);  // return n=deg(f)

void MulMod(zz_pEX& x, const zz_pEX& a, const zz_pEX& b,
            const zz_pEXModulus& F);
zz_pEX MulMod(const zz_pEX& a, const zz_pEX& b, const zz_pEXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F);
zz_pEX SqrMod(const zz_pEX& a, const zz_pEXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(zz_pEX& x, const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F);
zz_pEX PowerMod(const zz_pEX& a, const ZZ& e, const zz_pEXModulus& F);

void PowerMod(zz_pEX& x, const zz_pEX& a, long e, const zz_pEXModulus& F);
zz_pEX PowerMod(const zz_pEX& a, long e, const zz_pEXModulus& F);

// x = a^e % f; e >= 0, deg(a) < n.  Uses a sliding window algorithm.
// (e may be negative)

void PowerXMod(zz_pEX& x, const ZZ& e, const zz_pEXModulus& F);
zz_pEX PowerXMod(const ZZ& e, const zz_pEXModulus& F);

void PowerXMod(zz_pEX& x, long e, const zz_pEXModulus& F);
zz_pEX PowerXMod(long e, const zz_pEXModulus& F);

// x = X^e % f (e may be negative)

void rem(zz_pEX& x, const zz_pEX& a, const zz_pEXModulus& F);
// x = a % f

void DivRem(zz_pEX& q, zz_pEX& r, const zz_pEX& a, const zz_pEXModulus& F);
// q = a/f, r = a%f

void div(zz_pEX& q, const zz_pEX& a, const zz_pEXModulus& F);
// q = a/f

// operator notation:

zz_pEX operator/(const zz_pEX& a, const zz_pEXModulus& F);
zz_pEX operator%(const zz_pEX& a, const zz_pEXModulus& F);

zz_pEX& operator/=(zz_pEX& x, const zz_pEXModulus& F);
zz_pEX& operator%=(zz_pEX& x, const zz_pEXModulus& F);



/**************************************************************************\

                             vectors of zz_pEX's

\**************************************************************************/


typedef Vec<zz_pEX> vec_zz_pEX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.


\**************************************************************************/

void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEX& h,
             const zz_pEXModulus& F);
zz_pEX CompMod(const zz_pEX& g, const zz_pEX& h,
                    const zz_pEXModulus& F);

// x = g(h) mod f; deg(h) < n

void Comp2Mod(zz_pEX& x1, zz_pEX& x2, const zz_pEX& g1, const zz_pEX& g2,
              const zz_pEX& h, const zz_pEXModulus& F);
// xi = gi(h) mod f (i=1,2); deg(h) < n.


void Comp3Mod(zz_pEX& x1, zz_pEX& x2, zz_pEX& x3,
              const zz_pEX& g1, const zz_pEX& g2, const zz_pEX& g3,
              const zz_pEX& h, const zz_pEXModulus& F);
// xi = gi(h) mod f (i=1..3); deg(h) < n.



/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a zz_pEXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct zz_pEXArgument {
   vec_zz_pEX H;
};

void build(zz_pEXArgument& H, const zz_pEX& h, const zz_pEXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n.

void CompMod(zz_pEX& x, const zz_pEX& g, const zz_pEXArgument& H,
             const zz_pEXModulus& F);

zz_pEX CompMod(const zz_pEX& g, const zz_pEXArgument& H,
                    const zz_pEXModulus& F);

extern thread_local long zz_pEXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// zz_pEXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in zz_pEXFactoring.

/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(zz_pE& x, const zz_pEVector& a, const zz_pEX& b);
zz_pE project(const zz_pEVector& a, const zz_pEX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k,
                   const zz_pEX& h, const zz_pEXModulus& F);

vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k,
                   const zz_pEX& h, const zz_pEXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.

void ProjectPowers(vec_zz_pE& x, const vec_zz_pE& a, long k,
                   const zz_pEXArgument& H, const zz_pEXModulus& F);

vec_zz_pE ProjectPowers(const vec_zz_pE& a, long k,
                   const zz_pEXArgument& H, const zz_pEXModulus& F);

// same as above, but uses a pre-computed zz_pEXArgument


class zz_pEXTransMultiplier { /* ... */ };

void build(zz_pEXTransMultiplier& B, const zz_pEX& b, const zz_pEXModulus& F);

void UpdateMap(vec_zz_pE& x, const vec_zz_pE& a,
               const zz_pEXMultiplier& B, const zz_pEXModulus& F);

vec_zz_pE UpdateMap(const vec_zz_pE& a,
               const zz_pEXMultiplier& B, const zz_pEXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Required: a.length() <= deg(F), deg(b) < deg(F).
// This is "transposed" MulMod by B.
// Input may have "high order" zeroes stripped.
// Output always has high order zeroes stripped.


/**************************************************************************\

                              Minimum Polynomials

These routines should be used only when zz_pE is a field.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(zz_pEX& h, const vec_zz_pE& a, long m);
zz_pEX MinPolySeq(const vec_zz_pE& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m


void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void ProbMinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX ProbMinPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/2^{zz_pE::degree()}.

void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void MinPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX MinPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// same as above, but guarantees that result is correct

void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);
zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F, long m);

void IrredPolyMod(zz_pEX& h, const zz_pEX& g, const zz_pEXModulus& F);
zz_pEX IrredPolyMod(const zz_pEX& g, const zz_pEXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).

/**************************************************************************\

           Composition and Minimal Polynomials in towers

These are implementations of algorithms that will be described
and analyzed in a forthcoming paper.

The routines require that p is prime, but zz_pE need not be a field.

\**************************************************************************/


void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEXArgument& h,
             const zz_pEXModulus& F);

zz_pEX CompTower(const zz_pX& g, const zz_pEXArgument& h,
             const zz_pEXModulus& F);

void CompTower(zz_pEX& x, const zz_pX& g, const zz_pEX& h,
             const zz_pEXModulus& F);

zz_pEX CompTower(const zz_pX& g, const zz_pEX& h,
             const zz_pEXModulus& F);


// x = g(h) mod f


void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F,
                      long m);

zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void ProbMinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX ProbMinPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Uses a probabilistic algorithm to compute the minimal
// polynomial of (g mod f) over zz_p.
// The parameter m is a bound on the degree of the minimal polynomial
// (default = deg(f)*zz_pE::degree()).
// In general, the result will be a divisor of the true minimimal
// polynomial.  For correct results, use the MinPoly routines below.



void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);

zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void MinPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX MinPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Same as above, but result is always correct.


void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F, long m);

zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F, long m);

void IrredPolyTower(zz_pX& h, const zz_pEX& g, const zz_pEXModulus& F);

zz_pX IrredPolyTower(const zz_pEX& g, const zz_pEXModulus& F);

// Same as above, but assumes the minimal polynomial is
// irreducible, and uses a slightly faster, deterministic algorithm.


/**************************************************************************\

                   Traces, norms, resultants

\**************************************************************************/


void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEXModulus& F);
zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& F);

void TraceMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f);
zz_pE TraceMod(const zz_pEX& a, const zz_pEXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_zz_pE& S, const zz_pEX& f);
vec_zz_pE TraceVec(const zz_pEX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above trace routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(zz_pE& x, const zz_pEX& a, const zz_pEX& f);
zz_pE NormMod(const zz_pEX& a, const zz_pEX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)

void resultant(zz_pE& x, const zz_pEX& a, const zz_pEX& b);
zz_pE resultant(const zz_pEX& a, const zz_pEX& b);
// x = resultant(a, b)

// NormMod and resultant require that zz_pE is a field.




/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(zz_pEX& x) // x = 0
void set(zz_pEX& x); // x = 1

void zz_pEX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

zz_pEX::zz_pEX(INIT_SIZE_TYPE, long n);
// zz_pEX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const zz_pEX& zero();
// zz_pEX::zero() is a read-only reference to 0

void zz_pEX::swap(zz_pEX& x);
void swap(zz_pEX& x, zz_pEX& y);
// swap (via "pointer swapping")


zz_pEX::zz_pEX(long i, const zz_pE& c);
zz_pEX::zz_pEX(long i, const zz_p& c);
zz_pEX::zz_pEX(long i, long c);
// initilaize to c*X^i; provided for backward compatibility
ntl-11.5.1/doc/lzz_pEXFactoring.cpp.html0000644417616742025610000003124414064716023021626 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_pEXFactoring.cpp.html

/**************************************************************************\

MODULE: zz_pEXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over zz_pE, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include <NTL/lzz_pEX.h>
#include <NTL/pair_lzz_pEX_long.h>

void SquareFreeDecomp(vec_pair_zz_pEX_long& u, const zz_pEX& f);
vec_pair_zz_pEX_long SquareFreeDecomp(const zz_pEX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a list of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_zz_pE& x, const zz_pEX& f);
vec_zz_pE FindRoots(const zz_pEX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(zz_pE& root, const zz_pEX& f);
zz_pE FindRoot(const zz_pEX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void NewDDF(vec_pair_zz_pEX_long& factors, const zz_pEX& f,
            const zz_pEX& h, long verbose=0);

vec_pair_zz_pEX_long NewDDF(const zz_pEX& f, const zz_pEX& h,
         long verbose=0);


// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^{zz_pE::cardinality()} mod f.

// This routine implements the baby step/giant step algorithm
// of [Kaltofen and Shoup, STOC 1995].
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

// NOTE: When factoring "large" polynomials,
// this routine uses external files to store some intermediate
// results, which are removed if the routine terminates normally.
// These files are stored in the current directory under names of the
// form tmp-*.
// The definition of "large" is controlled by the variable

      extern thread_local double zz_pEXFileThresh

// which can be set by the user.  If the sizes of the tables
// exceeds zz_pEXFileThresh KB, external files are used.
// Initial value is NTL_FILE_THRESH (defined in tools.h).



void EDF(vec_zz_pEX& factors, const zz_pEX& f, const zz_pEX& h,
         long d, long verbose=0);

vec_zz_pEX EDF(const zz_pEX& f, const zz_pEX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^{zz_pE::cardinality()} mod
// f.  d = degree of irreducible factors of f.  This routine
// implements the algorithm of [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void RootEDF(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0);
vec_zz_pEX RootEDF(const zz_pEX& f, long verbose=0);

// EDF for d==1


void SFCanZass(vec_zz_pEX& factors, const zz_pEX& f, long verbose=0);
vec_zz_pEX SFCanZass(const zz_pEX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_zz_pEX_long& factors, const zz_pEX& f,
             long verbose=0);

vec_pair_zz_pEX_long CanZass(const zz_pEX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: these routines use modular composition.  The space
// used for the required tables can be controlled by the variable
// zz_pEXArgBound (see zz_pEX.txt).



void mul(zz_pEX& f, const vec_pair_zz_pEX_long& v);
zz_pEX mul(const vec_pair_zz_pEX_long& v);

// multiplies polynomials, with multiplicities


/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const zz_pEX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// zz_pE::cardinality()^{-iter}.  This implements an algorithm from [Shoup,
// J. Symbolic Comp. 17:371-391, 1994].

long DetIrredTest(const zz_pEX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const zz_pEX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(zz_pEX& f, long n);
zz_pEX BuildIrred_zz_pEX(long n);

// Build a monic irreducible poly of degree n. 

void BuildRandomIrred(zz_pEX& f, const zz_pEX& g);
zz_pEX BuildRandomIrred(const zz_pEX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.


long IterComputeDegree(const zz_pEX& h, const zz_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, and h =
// X^{zz_pE::cardinality()} mod f.  The common degree of the irreducible 
// factors of f is computed.  Uses a "baby step/giant step" algorithm, similar
// to NewDDF.  Although asymptotocally slower than RecComputeDegree
// (below), it is faster for reasonably sized inputs.

long RecComputeDegree(const zz_pEX& h, const zz_pEXModulus& F);

// f is assumed to be an "equal degree" polynomial, 
// h = X^{zz_pE::cardinality()} mod f.  
// The common degree of the irreducible factors of f is
// computed Uses a recursive algorithm similar to DetIrredTest.

void TraceMap(zz_pEX& w, const zz_pEX& a, long d, const zz_pEXModulus& F,
              const zz_pEX& h);

zz_pEX TraceMap(const zz_pEX& a, long d, const zz_pEXModulus& F,
              const zz_pEX& h);

// Computes w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0,
// and h = X^q mod f, q a power of zz_pE::cardinality().  This routine
// implements an algorithm from [von zur Gathen and Shoup,
// Computational Complexity 2:187-224, 1992]

void PowerCompose(zz_pEX& w, const zz_pEX& h, long d, const zz_pEXModulus& F);

zz_pEX PowerCompose(const zz_pEX& h, long d, const zz_pEXModulus& F);

// Computes w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q
// mod f, q a power of zz_pE::cardinality().  This routine implements an
// algorithm from [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]

ntl-11.5.1/doc/lzz_pX.cpp.html0000644417616742025610000015762714064716023017702 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_pX.cpp.html

/**************************************************************************\

MODULE: zz_pX

SUMMARY:

The class zz_pX implements polynomial arithmetic modulo p.

Polynomial arithmetic is implemented using a combination of classical
routines, Karatsuba, and FFT.

\**************************************************************************/

#include "zz_p.h"
#include "vec_zz_p.h"

class zz_pX {
public:

   zz_pX(); // initial value 0

   zz_pX(const zz_pX& a); // copy
   explicit zz_pX(zz_p a); // promotion
   explicit zz_pX(long a); // promotion

   zz_pX& operator=(const zz_pX& a); // assignment
   zz_pX& operator=(zz_p a);
   zz_pX& operator=(long a);

   ~zz_pX(); // destructor


   zz_pX(zz_pX&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set

#ifndef NTL_DISABLE_MOVE_ASSIGN
   zz_pX& operator=(zz_pX&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
#endif


   zz_pX(INIT_MONO_TYPE, long i, zz_p c);
   zz_pX(INIT_MONO_TYPE, long i, long c);
   // initialize to c*X^i, invoke as zz_pX(INIT_MONO, i, c)

   zz_pX(INIT_MONO_TYPE, long i);
   // initialize to X^i, invoke as zz_pX(INIT_MONO, i)

   typedef zz_p coeff_type;

   // ...


};





/**************************************************************************\

                              Accessing coefficients

The degree of a polynomial f is obtained as deg(f),
where the zero polynomial, by definition, has degree -1.

A polynomial f is represented as a coefficient vector.
Coefficients may be accesses in one of two ways.

The safe, high-level method is to call the function
coeff(f, i) to get the coefficient of X^i in the polynomial f,
and to call the function SetCoeff(f, i, a) to set the coefficient
of X^i in f to the scalar a.

One can also access the coefficients more directly via a lower level 
interface.  The coefficient of X^i in f may be accessed using 
subscript notation f[i].  In addition, one may write f.SetLength(n)
to set the length of the underlying coefficient vector to n,
and f.SetMaxLength(n) to allocate space for n coefficients,
without changing the coefficient vector itself.

After setting coefficients using this low-level interface,
one must ensure that leading zeros in the coefficient vector
are stripped afterwards by calling the function f.normalize().


NOTE: the coefficient vector of f may also be accessed directly
as f.rep; however, this is not recommended. Also, for a properly
normalized polynomial f, we have f.rep.length() == deg(f)+1,
and deg(f) >= 0  =>  f.rep[deg(f)] != 0.

\**************************************************************************/



long deg(const zz_pX& a);  // return deg(a); deg(0) == -1.

const zz_p coeff(const zz_pX& a, long i);
// returns the coefficient of X^i, or zero if i not in range

const zz_p LeadCoeff(const zz_pX& a);
// returns leading term of a, or zero if a == 0

const zz_p ConstTerm(const zz_pX& a);
// returns constant term of a, or zero if a == 0

void SetCoeff(zz_pX& x, long i, zz_p a);
void SetCoeff(zz_pX& x, long i, long a);
// makes coefficient of X^i equal to a; error is raised if i < 0

void SetCoeff(zz_pX& x, long i);
// makes coefficient of X^i equal to 1;  error is raised if i < 0

void SetX(zz_pX& x); // x is set to the monomial X

long IsX(const zz_pX& a); // test if x = X




zz_p& zz_pX::operator[](long i);
const zz_p& zz_pX::operator[](long i) const;
// indexing operators: f[i] is the coefficient of X^i ---
// i should satsify i >= 0 and i <= deg(f).
// No range checking (unless NTL_RANGE_CHECK is defined).

void zz_pX::SetLength(long n);
// f.SetLength(n) sets the length of the inderlying coefficient
// vector to n --- after this call, indexing f[i] for i = 0..n-1
// is valid.

void zz_pX::normalize();
// f.normalize() strips leading zeros from coefficient vector of f

void zz_pX::SetMaxLength(long n);
// f.SetMaxLength(n) pre-allocate spaces for n coefficients.  The
// polynomial that f represents is unchanged.





/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator==(const zz_pX& a, const zz_pX& b);
long operator!=(const zz_pX& a, const zz_pX& b);

long IsZero(const zz_pX& a); // test for 0
long IsOne(const zz_pX& a); // test for 1

// PROMOTIONS: operators ==, != promote {long, zz_p} to zz_pX on (a, b)


/**************************************************************************\

                                   Addition

\**************************************************************************/

// operator notation:

zz_pX operator+(const zz_pX& a, const zz_pX& b);
zz_pX operator-(const zz_pX& a, const zz_pX& b);

zz_pX operator-(const zz_pX& a); // unary -

zz_pX& operator+=(zz_pX& x, const zz_pX& a);
zz_pX& operator+=(zz_pX& x, zz_p a);
zz_pX& operator+=(zz_pX& x, long a);

zz_pX& operator-=(zz_pX& x, const zz_pX& a);
zz_pX& operator-=(zz_pX& x, zz_p a);
zz_pX& operator-=(zz_pX& x, long a);

zz_pX& operator++(zz_pX& x);  // prefix
void operator++(zz_pX& x, int);  // postfix

zz_pX& operator--(zz_pX& x);  // prefix
void operator--(zz_pX& x, int);  // postfix

// procedural versions:


void add(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a + b
void sub(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a - b
void negate(zz_pX& x, const zz_pX& a); // x = -a

// PROMOTIONS: binary +, - and procedures add, sub promote {long, zz_p}
// to zz_pX on (a, b).


/**************************************************************************\

                               Multiplication

\**************************************************************************/

// operator notation:

zz_pX operator*(const zz_pX& a, const zz_pX& b);

zz_pX& operator*=(zz_pX& x, const zz_pX& a);
zz_pX& operator*=(zz_pX& x, zz_p a);
zz_pX& operator*=(zz_pX& x, long a);

// procedural versions:


void mul(zz_pX& x, const zz_pX& a, const zz_pX& b); // x = a * b

void sqr(zz_pX& x, const zz_pX& a); // x = a^2
zz_pX sqr(const zz_pX& a);

// PROMOTIONS: operator * and procedure mul promote {long, zz_p} to zz_pX
// on (a, b).

void power(zz_pX& x, const zz_pX& a, long e);  // x = a^e (e >= 0)
zz_pX power(const zz_pX& a, long e);


/**************************************************************************\

                               Shift Operations

LeftShift by n means multiplication by X^n
RightShift by n means division by X^n

A negative shift amount reverses the direction of the shift.

\**************************************************************************/

// operator notation:

zz_pX operator<<(const zz_pX& a, long n);
zz_pX operator>>(const zz_pX& a, long n);

zz_pX& operator<<=(zz_pX& x, long n);
zz_pX& operator>>=(zz_pX& x, long n);

// procedural versions:

void LeftShift(zz_pX& x, const zz_pX& a, long n);
zz_pX LeftShift(const zz_pX& a, long n);

void RightShift(zz_pX& x, const zz_pX& a, long n);
zz_pX RightShift(const zz_pX& a, long n);



/**************************************************************************\

                                  Division

\**************************************************************************/

// operator notation:

zz_pX operator/(const zz_pX& a, const zz_pX& b);
zz_pX operator%(const zz_pX& a, const zz_pX& b);

zz_pX& operator/=(zz_pX& x, const zz_pX& a);
zz_pX& operator/=(zz_pX& x, zz_p a);
zz_pX& operator/=(zz_pX& x, long a);

zz_pX& operator%=(zz_pX& x, const zz_pX& b);


// procedural versions:


void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pX& b);
// q = a/b, r = a%b

void div(zz_pX& q, const zz_pX& a, const zz_pX& b);
// q = a/b

void rem(zz_pX& r, const zz_pX& a, const zz_pX& b);
// r = a%b

long divide(zz_pX& q, const zz_pX& a, const zz_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

long divide(const zz_pX& a, const zz_pX& b);
// if b | a, sets q = a/b and returns 1; otherwise returns 0

// PROMOTIONS: operator / and procedure div promote {long, zz_p} to zz_pX
// on (a, b).


/**************************************************************************\

                                   GCD's

These routines are intended for use when p is prime.

\**************************************************************************/


void GCD(zz_pX& x, const zz_pX& a, const zz_pX& b);
zz_pX GCD(const zz_pX& a, const zz_pX& b);
// x = GCD(a, b),  x is always monic (or zero if a==b==0).


void XGCD(zz_pX& d, zz_pX& s, zz_pX& t, const zz_pX& a, const zz_pX& b);
// d = gcd(a,b), a s + b t = d 


// NOTE: A classical algorithm is used, switching over to a
// "half-GCD" algorithm for large degree


/**************************************************************************\

                                  Input/Output

I/O format:

   [a_0 a_1 ... a_n],

represents the polynomial a_0 + a_1*X + ... + a_n*X^n.

On output, all coefficients will be integers between 0 and p-1, amd
a_n not zero (the zero polynomial is [ ]).  On input, the coefficients
are arbitrary integers which are reduced modulo p, and leading zeros
stripped.

\**************************************************************************/

istream& operator>>(istream& s, zz_pX& x);
ostream& operator<<(ostream& s, const zz_pX& a);


/**************************************************************************\

                              Some utility routines

\**************************************************************************/


void diff(zz_pX& x, const zz_pX& a);
zz_pX diff(const zz_pX& a);
// x = derivative of a


void MakeMonic(zz_pX& x);
// if x != 0 makes x into its monic associate; LeadCoeff(x) must be
// invertible in this case.

void reverse(zz_pX& x, const zz_pX& a, long hi);
zz_pX reverse(const zz_pX& a, long hi);

void reverse(zz_pX& x, const zz_pX& a);
zz_pX reverse(const zz_pX& a);

// x = reverse of a[0]..a[hi] (hi >= -1);
// hi defaults to deg(a) in second version

void VectorCopy(vec_zz_p& x, const zz_pX& a, long n);
vec_zz_p VectorCopy(const zz_pX& a, long n);
// x = copy of coefficient vector of a of length exactly n.
// input is truncated or padded with zeroes as appropriate.





/**************************************************************************\

                             Random Polynomials

\**************************************************************************/

void random(zz_pX& x, long n);
zz_pX random_zz_pX(long n);
// x = random polynomial of degree < n 


/**************************************************************************\

                    Polynomial Evaluation and related problems

\**************************************************************************/


void BuildFromRoots(zz_pX& x, const vec_zz_p& a);
zz_pX BuildFromRoots(const vec_zz_p& a);
// computes the polynomial (X-a[0]) ... (X-a[n-1]), where n =
// a.length()

void eval(zz_p& b, const zz_pX& f, zz_p a);
zz_p eval(const zz_pX& f, zz_p a);
// b = f(a)

void eval(vec_zz_p& b, const zz_pX& f, const vec_zz_p& a);
vec_zz_p eval(const zz_pX& f, const vec_zz_p& a);
//  b.SetLength(a.length());  b[i] = f(a[i]) for 0 <= i < a.length()

void interpolate(zz_pX& f, const vec_zz_p& a, const vec_zz_p& b);
zz_pX interpolate(const vec_zz_p& a, const vec_zz_p& b);
// interpolates the polynomial f satisfying f(a[i]) = b[i].  p should
// be prime.

/**************************************************************************\

                       Arithmetic mod X^n

It is required that n >= 0, otherwise an error is raised.

\**************************************************************************/

void trunc(zz_pX& x, const zz_pX& a, long n); // x = a % X^n
zz_pX trunc(const zz_pX& a, long n);

void MulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n);
zz_pX MulTrunc(const zz_pX& a, const zz_pX& b, long n);
// x = a * b % X^n

void SqrTrunc(zz_pX& x, const zz_pX& a, long n);
zz_pX SqrTrunc(const zz_pX& a, long n);
// x = a^2 % X^n

void InvTrunc(zz_pX& x, const zz_pX& a, long n);
zz_pX InvTrunc(const zz_pX& a, long n);
// computes x = a^{-1} % X^n.  Must have ConstTerm(a) invertible.

/**************************************************************************\

                Modular Arithmetic (without pre-conditioning)

Arithmetic mod f.

All inputs and outputs are polynomials of degree less than deg(f), and
deg(f) > 0.

NOTE: if you want to do many computations with a fixed f, use the
zz_pXModulus data structure and associated routines below for better
performance.

\**************************************************************************/

void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pX& f);
zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pX& f);
// x = (a * b) % f

void SqrMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX SqrMod(const zz_pX& a, const zz_pX& f);
// x = a^2 % f

void MulByXMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX MulByXMod(const zz_pX& a, const zz_pX& f);
// x = (a * X) mod f

void InvMod(zz_pX& x, const zz_pX& a, const zz_pX& f);
zz_pX InvMod(const zz_pX& a, const zz_pX& f);
// x = a^{-1} % f, error is a is not invertible

long InvModStatus(zz_pX& x, const zz_pX& a, const zz_pX& f);
// if (a, f) = 1, returns 0 and sets x = a^{-1} % f; otherwise,
// returns 1 and sets x = (a, f)


// for modular exponentiation, see below



/**************************************************************************\

                     Modular Arithmetic with Pre-Conditioning

If you need to do a lot of arithmetic modulo a fixed f, build
zz_pXModulus F for f.  This pre-computes information about f that
speeds up subsequent computations. Required: deg(f) > 0 and LeadCoeff(f)
invertible.

As an example, the following routine computes the product modulo f of a vector
of polynomials.

#include "zz_pX.h"

void product(zz_pX& x, const vec_zz_pX& v, const zz_pX& f)
{
   zz_pXModulus F(f);
   zz_pX res;
   res = 1;
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(res, res, v[i], F); 
   x = res;
}


Note that automatic conversions are provided so that a zz_pX can
be used wherever a zz_pXModulus is required, and a zz_pXModulus
can be used wherever a zz_pX is required.



\**************************************************************************/

class zz_pXModulus {
public:
   zz_pXModulus(); // initially in an unusable state
   ~zz_pXModulus();

   zz_pXModulus(const zz_pXModulus&);  // copy

   zz_pXModulus& operator=(const zz_pXModulus&);  // assignment

   zz_pXModulus(const zz_pX& f); // initialize with f, deg(f) > 0

   operator const zz_pX& () const;
   // read-only access to f, implicit conversion operator

   const zz_pX& val() const;
   // read-only access to f, explicit notation

};

void build(zz_pXModulus& F, const zz_pX& f);
// pre-computes information about f and stores it in F.
// Note that the declaration zz_pXModulus F(f) is equivalent to
// zz_pXModulus F; build(F, f).

// In the following, f refers to the polynomial f supplied to the
// build routine, and n = deg(f).

long deg(const zz_pXModulus& F);  // return deg(f)

void MulMod(zz_pX& x, const zz_pX& a, const zz_pX& b, const zz_pXModulus& F);
zz_pX MulMod(const zz_pX& a, const zz_pX& b, const zz_pXModulus& F);
// x = (a * b) % f; deg(a), deg(b) < n

void SqrMod(zz_pX& x, const zz_pX& a, const zz_pXModulus& F);
zz_pX SqrMod(const zz_pX& a, const zz_pXModulus& F);
// x = a^2 % f; deg(a) < n

void PowerMod(zz_pX& x, const zz_pX& a, const ZZ& e, const zz_pXModulus& F);
zz_pX PowerMod(const zz_pX& a, const ZZ& e, const zz_pXModulus& F);

void PowerMod(zz_pX& x, const zz_pX& a, long e, const zz_pXModulus& F);
zz_pX PowerMod(const zz_pX& a, long e, const zz_pXModulus& F);

// x = a^e % f; deg(a) < n (e may be negative)

void PowerXMod(zz_pX& x, const ZZ& e, const zz_pXModulus& F);
zz_pX PowerXMod(const ZZ& e, const zz_pXModulus& F);

void PowerXMod(zz_pX& x, long e, const zz_pXModulus& F);
zz_pX PowerXMod(long e, const zz_pXModulus& F);

// x = X^e % f (e may be negative)

void PowerXPlusAMod(zz_pX& x, const zz_p& a, const ZZ& e,
                    const zz_pXModulus& F);

zz_pX PowerXPlusAMod(const zz_p& a, const ZZ& e,
                           const zz_pXModulus& F);

void PowerXPlusAMod(zz_pX& x, const zz_p& a, long e,
                    const zz_pXModulus& F);

zz_pX PowerXPlusAMod(const zz_p& a, long e,
                           const zz_pXModulus& F);

// x = (X + a)^e % f (e may be negative)


void rem(zz_pX& x, const zz_pX& a, const zz_pXModulus& F);
// x = a % f

void DivRem(zz_pX& q, zz_pX& r, const zz_pX& a, const zz_pXModulus& F);
// q = a/f, r = a%f

void div(zz_pX& q, const zz_pX& a, const zz_pXModulus& F);
// q = a/f

// operator notation:

zz_pX operator/(const zz_pX& a, const zz_pXModulus& F);
zz_pX operator%(const zz_pX& a, const zz_pXModulus& F);

zz_pX& operator/=(zz_pX& x, const zz_pXModulus& F);
zz_pX& operator%=(zz_pX& x, const zz_pXModulus& F);




/**************************************************************************\


                        More Pre-Conditioning

If you need to compute a * b % f for a fixed b, but for many a's, it
is much more efficient to first build a zz_pXMultiplier B for b, and
then use the MulMod routine below.

Here is an example that multiplies each element of a vector by a fixed
polynomial modulo f.

#include "zz_pX.h"

void mul(vec_zz_pX& v, const zz_pX& b, const zz_pX& f)
{
   zz_pXModulus F(f);
   zz_pXMultiplier B(b, F);
   long i;
   for (i = 0; i < v.length(); i++)
      MulMod(v[i], v[i], B, F);
}

Note that a (trivial) conversion operator from zz_pXMultiplier to zz_pX
is provided, so that a zz_pXMultiplier can be used in a context
where a zz_pX is required.


\**************************************************************************/


class zz_pXMultiplier {
public:
   zz_pXMultiplier(); // initially zero

   zz_pXMultiplier(const zz_pX& b, const zz_pXModulus& F);
      // initializes with b mod F, where deg(b) < deg(F)

   zz_pXMultiplier(const zz_pXMultiplier&);
   zz_pXMultiplier& operator=(const zz_pXMultiplier&);

   ~zz_pXMultiplier();

   const zz_pX& val() const; // read-only access to b

};

void build(zz_pXMultiplier& B, const zz_pX& b, const zz_pXModulus& F);
// pre-computes information about b and stores it in B; deg(b) <
// deg(F)

void MulMod(zz_pX& x, const zz_pX& a, const zz_pXMultiplier& B,
                                      const zz_pXModulus& F);

zz_pX MulMod(const zz_pX& a, const zz_pXMultiplier& B,
             const zz_pXModulus& F);

// x = (a * b) % F; deg(a) < deg(F)

/**************************************************************************\

                             vectors of zz_pX's

\**************************************************************************/


typedef Vec<zz_pX> vec_zz_pX; // backward compatibility



/**************************************************************************\

                              Modular Composition

Modular composition is the problem of computing g(h) mod f for
polynomials f, g, and h.

The algorithm employed is that of Brent & Kung (Fast algorithms for
manipulating formal power series, JACM 25:581-595, 1978), which uses
O(n^{1/2}) modular polynomial multiplications, and O(n^2) scalar
operations.



\**************************************************************************/

void CompMod(zz_pX& x, const zz_pX& g, const zz_pX& h, const zz_pXModulus& F);
zz_pX CompMod(const zz_pX& g, const zz_pX& h, const zz_pXModulus& F);
// x = g(h) mod f; deg(h) < n

void Comp2Mod(zz_pX& x1, zz_pX& x2, const zz_pX& g1, const zz_pX& g2,
              const zz_pX& h, const zz_pXModulus& F);
// xi = gi(h) mod f (i=1,2), deg(h) < n.

void CompMod3(zz_pX& x1, zz_pX& x2, zz_pX& x3,
              const zz_pX& g1, const zz_pX& g2, const zz_pX& g3,
              const zz_pX& h, const zz_pXModulus& F);
// xi = gi(h) mod f (i=1..3), deg(h) < n


/**************************************************************************\

                     Composition with Pre-Conditioning

If a single h is going to be used with many g's then you should build
a zz_pXArgument for h, and then use the compose routine below.  The
routine build computes and stores h, h^2, ..., h^m mod f.  After this
pre-computation, composing a polynomial of degree roughly n with h
takes n/m multiplies mod f, plus n^2 scalar multiplies.  Thus,
increasing m increases the space requirement and the pre-computation
time, but reduces the composition time.

\**************************************************************************/


struct zz_pXArgument {
   vec_zz_pX H;
};

void build(zz_pXArgument& H, const zz_pX& h, const zz_pXModulus& F, long m);
// Pre-Computes information about h.  m > 0, deg(h) < n

void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& H,
             const zz_pXModulus& F);

zz_pX CompMod(const zz_pX& g, const zz_pXArgument& H,
             const zz_pXModulus& F);


extern thread_local long zz_pXArgBound;

// Initially 0.  If this is set to a value greater than zero, then
// composition routines will allocate a table of no than about
// zz_pXArgBound KB.  Setting this value affects all compose routines
// and the power projection and minimal polynomial routines below, 
// and indirectly affects many routines in zz_pXFactoring.


/**************************************************************************\

                     power projection routines

\**************************************************************************/

void project(zz_p& x, const zz_pVector& a, const zz_pX& b);
zz_p project(const zz_pVector& a, const zz_pX& b);
// x = inner product of a with coefficient vector of b


void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k,
                   const zz_pX& h, const zz_pXModulus& F);

vec_zz_p ProjectPowers(const vec_zz_p& a, long k,
                   const zz_pX& h, const zz_pXModulus& F);

// Computes the vector

//    project(a, 1), project(a, h), ..., project(a, h^{k-1} % f).  

// This operation is the "transpose" of the modular composition operation.
// Input and output may have "high order" zeroes stripped.

void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k,
                   const zz_pXArgument& H, const zz_pXModulus& F);

vec_zz_p ProjectPowers(const vec_zz_p& a, long k,
                   const zz_pXArgument& H, const zz_pXModulus& F);

// same as above, but uses a pre-computed zz_pXArgument


void UpdateMap(vec_zz_p& x, const vec_zz_p& a,
               const zz_pXMultiplier& B, const zz_pXModulus& F);

vec_zz_p UpdateMap(const vec_zz_p& a,
               const zz_pXMultiplier& B, const zz_pXModulus& F);

// Computes the vector

//    project(a, b), project(a, (b*X)%f), ..., project(a, (b*X^{n-1})%f)

// Restriction: a.length() <= deg(F).
// This is "transposed" MulMod by B.
// Input vector may have "high order" zeroes striped.
// The output will always have high order zeroes stripped.


/**************************************************************************\

        Faster Composition and Projection with Pre-Conditioning

A new, experimental version of composition with preconditioning.
This interface was introduced in NTL v10.2.0, and it should be 
considered a preliminary interface and subject to change.

The class zz_pXNewArgument is similar to zz_pXArgument, but with
a different internal layout.  Copy constructor and assignment work.

Note that all NTL modular composition and power projection routines, 
as well as other routines that use modular composition power projection 
internally, now use this new class.

Note also that these routines do not pay any attention to the
zz_pXArgBound variable.

\**************************************************************************/

class zz_pXNewArgument {
 // ...
};

void build(zz_pXNewArgument& H, const zz_pX& h, const zz_pXModulus& F, long m);
// same functionality as the corresponding zz_pXArgument-based routine

void CompMod(zz_pX& x, const zz_pX& g, const zz_pXNewArgument& H,
             const zz_pXModulus& F);
// same functionality as the corresponding zz_pXArgument-based routine

void ProjectPowers(vec_zz_p& x, const vec_zz_p& a, long k,
                   const zz_pXNewArgument& H, const zz_pXModulus& F);
// same functionality as the corresponding zz_pXArgument-based routine



/**************************************************************************\

                              Minimum Polynomials

These routines should be used with prime p.

All of these routines implement the algorithm from [Shoup, J. Symbolic
Comp. 17:371-391, 1994] and [Shoup, J. Symbolic Comp. 20:363-397,
1995], based on transposed modular composition and the
Berlekamp/Massey algorithm.

\**************************************************************************/


void MinPolySeq(zz_pX& h, const vec_zz_p& a, long m);
// computes the minimum polynomial of a linealy generated sequence; m
// is a bound on the degree of the polynomial; required: a.length() >=
// 2*m

void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m);

void ProbMinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX ProbMinPolyMod(const zz_pX& g, const zz_pXModulus& F);

// computes the monic minimal polynomial if (g mod f).  m = a bound on
// the degree of the minimal polynomial; in the second version, this
// argument defaults to n.  The algorithm is probabilistic, always
// returns a divisor of the minimal polynomial, and returns a proper
// divisor with probability at most m/p.

void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F, long m);

void MinPolyMod(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX MinPolyMod(const zz_pX& g, const zz_pXModulus& F);
// same as above, but guarantees that result is correct

void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F, long m);
zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F, long m);

void IrredPoly(zz_pX& h, const zz_pX& g, const zz_pXModulus& F);
zz_pX IrredPoly(const zz_pX& g, const zz_pXModulus& F);

// same as above, but assumes that f is irreducible, or at least that
// the minimal poly of g is itself irreducible.  The algorithm is
// deterministic (and is always correct).


/**************************************************************************\

                   Traces, norms, resultants

These routines should be used with prime p.

\**************************************************************************/


void TraceMod(zz_p& x, const zz_pX& a, const zz_pXModulus& F);
zz_p TraceMod(const zz_pX& a, const zz_pXModulus& F);

void TraceMod(zz_p& x, const zz_pX& a, const zz_pX& f);
zz_p TraceMod(const zz_pX& a, const zz_pXModulus& f);
// x = Trace(a mod f); deg(a) < deg(f)


void TraceVec(vec_zz_p& S, const zz_pX& f);
vec_zz_p TraceVec(const zz_pX& f);
// S[i] = Trace(X^i mod f), i = 0..deg(f)-1; 0 < deg(f)

// The above routines implement the asymptotically fast trace
// algorithm from [von zur Gathen and Shoup, Computational Complexity,
// 1992].

void NormMod(zz_p& x, const zz_pX& a, const zz_pX& f);
zz_p NormMod(const zz_pX& a, const zz_pX& f);
// x = Norm(a mod f); 0 < deg(f), deg(a) < deg(f)


void resultant(zz_p& x, const zz_pX& a, const zz_pX& b);
zz_pX resultant(zz_p& x, const zz_pX& a, const zz_pX& b);
// x = resultant(a, b)


void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& f);
zz_pX CharPolyMod(const zz_pX& a, const zz_pX& f);
// g = charcteristic polynomial of (a mod f); 0 < deg(f), deg(g) <
// deg(f).  This routine works for arbitrary f.  For irreducible f,
// is it faster to use IrredPolyMod, and then exponentiate as
// necessary, since in this case the characterstic polynomial
// is a power of the minimal polynomial.


/**************************************************************************\

                           Miscellany


\**************************************************************************/


void clear(zz_pX& x) // x = 0
void set(zz_pX& x); // x = 1

void zz_pX::kill();
// f.kill() sets f to 0 and frees all memory held by f.  Equivalent to
// f.rep.kill().

zz_pX::zz_pX(INIT_SIZE_TYPE, long n);
// zz_pX(INIT_SIZE, n) initializes to zero, but space is pre-allocated
// for n coefficients

static const zz_pX& zero();
// zz_pX::zero() is a read-only reference to 0

void swap(zz_pX& x, zz_pX& y);
// swap x and y (via "pointer swapping")


zz_pX::zz_pX(long i, zz_p c);
zz_pX::zz_pX(long i, long c);
 // initialize to c*X^i, provided for backward compatibility
ntl-11.5.1/doc/lzz_pXFactoring.cpp.html0000644417616742025610000003044614064716023021524 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/lzz_pXFactoring.cpp.html

/**************************************************************************\

MODULE: zz_pXFactoring

SUMMARY:

Routines are provided for factorization of polynomials over zz_p, as
well as routines for related problems such as testing irreducibility
and constructing irreducible polynomials of given degree.

\**************************************************************************/

#include "zz_pX.h"
#include "pair_zz_pX_long.h"


void SquareFreeDecomp(vec_pair_zz_pX_long& u, const zz_pX& f);
vec_pair_zz_pX_long SquareFreeDecomp(const zz_pX& f);

// Performs square-free decomposition.  f must be monic.  If f =
// prod_i g_i^i, then u is set to a lest of pairs (g_i, i).  The list
// is is increasing order of i, with trivial terms (i.e., g_i = 1)
// deleted.


void FindRoots(vec_zz_p& x, const zz_pX& f);
vec_zz_p FindRoots(const zz_pX& f);

// f is monic, and has deg(f) distinct roots.  returns the list of
// roots

void FindRoot(zz_p& root, const zz_pX& f);
zz_p FindRoot(const zz_pX& f);

// finds a single root of f.  assumes that f is monic and splits into
// distinct linear factors


void SFBerlekamp(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX  SFBerlekamp(const zz_pX& f, long verbose=0);

// Assumes f is square-free and monic.  returns list of factors of f.
// Uses "Berlekamp" approach, as described in detail in [Shoup,
// J. Symbolic Comp. 20:363-397, 1995].

void berlekamp(vec_pair_zz_pX_long& factors, const zz_pX& f,
               long verbose=0);
vec_pair_zz_pX_long berlekamp(const zz_pX& f, long verbose=0);

// returns a list of factors, with multiplicities.  f must be monic.
// Calls SFBerlekamp.



void NewDDF(vec_pair_zz_pX_long& factors, const zz_pX& f, const zz_pX& h,
         long verbose=0);

vec_pair_zz_pX_long NewDDF(const zz_pX& f, const zz_pX& h,
         long verbose=0);

// This computes a distinct-degree factorization.  The input must be
// monic and square-free.  factors is set to a list of pairs (g, d),
// where g is the product of all irreducible factors of f of degree d.
// Only nontrivial pairs (i.e., g != 1) are included.  The polynomial
// h is assumed to be equal to X^p mod f.  This routine implements the
// baby step/giant step algorithm of [Kaltofen and Shoup, STOC 1995],
// further described in [Shoup, J. Symbolic Comp. 20:363-397, 1995].

void EDF(vec_zz_pX& factors, const zz_pX& f, const zz_pX& h,
         long d, long verbose=0);

vec_zz_pX EDF(const zz_pX& f, const zz_pX& h,
         long d, long verbose=0);

// Performs equal-degree factorization.  f is monic, square-free, and
// all irreducible factors have same degree.  h = X^p mod f.  d =
// degree of irreducible factors of f.  This routine implements the
// algorithm of [von zur Gathen and Shoup, Computational Complexity
// 2:187-224, 1992]


void RootEDF(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX RootEDF(const zz_pX& f, long verbose=0);

// EDF for d==1

void SFCanZass(vec_zz_pX& factors, const zz_pX& f, long verbose=0);
vec_zz_pX SFCanZass(const zz_pX& f, long verbose=0);

// Assumes f is monic and square-free.  returns list of factors of f.
// Uses "Cantor/Zassenhaus" approach, using the routines NewDDF and
// EDF above.


void CanZass(vec_pair_zz_pX_long& factors, const zz_pX& f,
             long verbose=0);
vec_pair_zz_pX_long CanZass(const zz_pX& f, long verbose=0);


// returns a list of factors, with multiplicities.  f must be monic.
// Calls SquareFreeDecomp and SFCanZass.

// NOTE: In most situations, you should use the CanZass factoring
// routine, rather than Berlekamp: it is faster and uses less space.


void mul(zz_pX& f, const vec_pair_zz_pX_long& v);
zz_pX mul(const vec_pair_zz_pX_long& v);


// multiplies polynomials, with multiplicities

/**************************************************************************\

                            Irreducible Polynomials

\**************************************************************************/

long ProbIrredTest(const zz_pX& f, long iter=1);

// performs a fast, probabilistic irreduciblity test.  The test can
// err only if f is reducible, and the error probability is bounded by
// p^{-iter}.  This implements an algorithm from [Shoup, J. Symbolic
// Comp. 17:371-391, 1994].


long DetIrredTest(const zz_pX& f);

// performs a recursive deterministic irreducibility test.  Fast in
// the worst-case (when input is irreducible).  This implements an
// algorithm from [Shoup, J. Symbolic Comp. 17:371-391, 1994].

long IterIrredTest(const zz_pX& f);

// performs an iterative deterministic irreducibility test, based on
// DDF.  Fast on average (when f has a small factor).

void BuildIrred(zz_pX& f, long n);
zz_pX BuildIrred_zz_pX(long n);

// Build a monic irreducible poly of degree n.

void BuildRandomIrred(zz_pX& f, const zz_pX& g);
zz_pX BuildRandomIrred(const zz_pX& g);

// g is a monic irreducible polynomial.  Constructs a random monic
// irreducible polynomial f of the same degree.

long ComputeDegree(const zz_pX& h, const zz_pXModulus& F);

// f is assumed to be an "equal degree" polynomial.  h = X^p mod f.
// The common degree of the irreducible factors of f is computed This
// routine is useful in counting points on elliptic curves

long ProbComputeDegree(const zz_pX& h, const zz_pXModulus& F);

// same as above, but uses a slightly faster probabilistic algorithm.
// The return value may be 0 or may be too big, but for large p
// (relative to n), this happens with very low probability.

void TraceMap(zz_pX& w, const zz_pX& a, long d, const zz_pXModulus& F,
              const zz_pX& h);

zz_pX TraceMap(const zz_pX& a, long d, const zz_pXModulus& F,
              const zz_pX& h);

// w = a+a^q+...+^{q^{d-1}} mod f; it is assumed that d >= 0, and h =
// X^q mod f, q a power of p.  This routine implements an algorithm
// from [von zur Gathen and Shoup, Computational Complexity 2:187-224,
// 1992]

void PowerCompose(zz_pX& w, const zz_pX& h, long d, const zz_pXModulus& F);
zz_pX PowerCompose(const zz_pX& h, long d, const zz_pXModulus& F);


// w = X^{q^d} mod f; it is assumed that d >= 0, and h = X^q mod f, q
// a power of p.  This routine implements an algorithm from [von zur
// Gathen and Shoup, Computational Complexity 2:187-224, 1992]

ntl-11.5.1/doc/mat_GF2.cpp.html0000644417616742025610000002527614064716023017625 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_GF2.cpp.html

/**************************************************************************\

MODULE: mat_GF2

SUMMARY:

Defines the class mat_GF2.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_GF2.h>


typedef Mat<GF2> mat_GF2; // backward compatibility


void conv(mat_GF2& X, const vec_vec_GF2& A);
mat_GF2 to_mat_GF2(const vec_vec_GF2& A);
// convert a vector of vec_GF2's to a matrix


// procedural arithmetic routines:

void add(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A + B

void sub(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A - B = A + B

void negate(mat_GF2& X, const mat_GF2& A);
// X = -A = A 

void mul(mat_GF2& X, const mat_GF2& A, const mat_GF2& B);
// X = A * B

void mul(vec_GF2& x, const mat_GF2& A, const vec_GF2& b);
// x = A * b

void mul(vec_GF2& x, const vec_GF2& a, const mat_GF2& B);
// x = a * B


void mul(mat_GF2& X, const mat_GF2& A, GF2 b);
void mul(mat_GF2& X, const mat_GF2& A, long b);
// X = A * b

void mul(mat_GF2& X, GF2 a, const mat_GF2& B);
void mul(mat_GF2& X, long a, const mat_GF2& B);
// X = a * B

void determinant(GF2& d, const mat_GF2& A);
GF2 determinant(const mat_GF2& A);
// d =  determinant of A

void transpose(mat_GF2& X, const mat_GF2& A);
mat_GF2 transpose(const mat_GF2& A);
// X = transpose of A

void solve(GF2& d, vec_GF2& x, const mat_GF2& A, const vec_GF2& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves x*A = b. 

void solve(GF2& d, const mat_GF2& A, vec_GF2& x, const vec_GF2& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(GF2& d, mat_GF2& X, const mat_GF2& A);
// A is an n x n matrix.  Computes d = det(A).  If d != 0,
// computes X = A^{-1}. 

void sqr(mat_GF2& X, const mat_GF2& A);
mat_GF2 sqr(const mat_GF2& A);
// X = A*A   

void inv(mat_GF2& X, const mat_GF2& A);
mat_GF2 inv(const mat_GF2& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_GF2& X, const mat_GF2& A, const ZZ& e);
mat_GF2 power(const mat_GF2& A, const ZZ& e);

void power(mat_GF2& X, const mat_GF2& A, long e);
mat_GF2 power(const mat_GF2& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).


void ident(mat_GF2& X, long n);
mat_GF2 ident_mat_GF2(long n);
// X = n x n identity matrix

long IsIdent(const mat_GF2& A, long n);
// test if A is n x n identity matrix


void diag(mat_GF2& X, long n, GF2 d);
mat_GF2 diag(long n, GF2 d);
// X = n x n diagonal matrix with diagonal element d

long IsDiag(const mat_GF2& A, long n, long d);
// test if X is an n x n diagonal matrix with diagonal element (d mod 2)


void random(mat_GF2& x, long n, long m);  // x = random n x m matrix
mat_GF2 random_mat_GF2(long n, long m);

long gauss(mat_GF2& M);
long gauss(mat_GF2& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_GF2& X, const mat_GF2& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form


void kernel(mat_GF2& X, const mat_GF2& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.

// miscellaneous:


void clear(mat_GF2& X);
// X = 0 (dimension unchanged)

long IsZero(const mat_GF2& A);
// test if A is the zero matrix (any dimension)


// arithmetic operator notation:

mat_GF2 operator+(const mat_GF2& a, const mat_GF2& b);
mat_GF2 operator-(const mat_GF2& a, const mat_GF2& b);
mat_GF2 operator*(const mat_GF2& a, const mat_GF2& b);

mat_GF2 operator-(const mat_GF2& a);


// matrix/scalar multiplication:

mat_GF2 operator*(const mat_GF2& a, GF2 b);
mat_GF2 operator*(const mat_GF2& a, long b);

mat_GF2 operator*(GF2 a, const mat_GF2& b);
mat_GF2 operator*(long a, const mat_GF2& b);

// matrix/vector multiplication:

vec_GF2 operator*(const mat_GF2& a, const vec_GF2& b);

vec_GF2 operator*(const vec_GF2& a, const mat_GF2& b);


// assignment operator notation:

mat_GF2& operator+=(mat_GF2& x, const mat_GF2& a);
mat_GF2& operator-=(mat_GF2& x, const mat_GF2& a);
mat_GF2& operator*=(mat_GF2& x, const mat_GF2& a);

mat_GF2& operator*=(mat_GF2& x, GF2 a);
mat_GF2& operator*=(mat_GF2& x, long a);

vec_GF2& operator*=(vec_GF2& x, const mat_GF2& a);


ntl-11.5.1/doc/mat_GF2E.cpp.html0000644417616742025610000002640414064716023017724 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_GF2E.cpp.html

/**************************************************************************\

MODULE: mat_GF2E

SUMMARY:

Defines the class mat_GF2E.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_GF2E.h>


typedef Mat<GF2E> mat_GF2E; // backward compatibility


void add(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A + B

void sub(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A - B = A + B

void negate(mat_GF2E& X, const mat_GF2E& A);
// X = - A  = A

void mul(mat_GF2E& X, const mat_GF2E& A, const mat_GF2E& B);
// X = A * B

void mul(vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b);
// x = A * b

void mul(vec_GF2E& x, const vec_GF2E& a, const mat_GF2E& B);
// x = a * B

void mul(mat_GF2E& X, const mat_GF2E& A, const GF2E& b);
void mul(mat_GF2E& X, const mat_GF2E& A, GF2 b);
void mul(mat_GF2E& X, const mat_GF2E& A, long b);
// X = A * b

void mul(mat_GF2E& X, const GF2E& a, const mat_GF2E& B);
void mul(mat_GF2E& X, GF2 a, const mat_GF2E& B);
void mul(mat_GF2E& X, long a, const mat_GF2E& B);
// X = a * B



void determinant(GF2E& d, const mat_GF2E& A);
GF2E determinant(const mat_GF2E& a);
// d = determinant(A)


void transpose(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E transpose(const mat_GF2E& A);
// X = transpose of A

void solve(GF2E& d, vec_GF2E& x, const mat_GF2E& A, const vec_GF2E& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves x*A = b.

void solve(GF2E& d, const mat_GF2E& A, vec_GF2E& x, const vec_GF2E& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(GF2E& d, mat_GF2E& X, const mat_GF2E& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E sqr(const mat_GF2E& A);
// X = A*A   

void inv(mat_GF2E& X, const mat_GF2E& A);
mat_GF2E inv(const mat_GF2E& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_GF2E& X, const mat_GF2E& A, const ZZ& e);
mat_GF2E power(const mat_GF2E& A, const ZZ& e);

void power(mat_GF2E& X, const mat_GF2E& A, long e);
mat_GF2E power(const mat_GF2E& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).


void ident(mat_GF2E& X, long n);
mat_GF2E ident_mat_GF2E(long n);
// X = n x n identity matrix

long IsIdent(const mat_GF2E& A, long n);
// test if A is the n x n identity matrix

void diag(mat_GF2E& X, long n, const GF2E& d);
mat_GF2E diag(long n, const GF2E& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_GF2E& A, long n, const GF2E& d);
// test if X is an  n x n diagonal matrix with d on diagonal



void random(mat_GF2E& x, long n, long m);  // x = random n x m matrix
mat_GF2E random_mat_GF2E(long n, long m);



long gauss(mat_GF2E& M);
long gauss(mat_GF2E& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_GF2E& X, const mat_GF2E& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_GF2E& X, const mat_GF2E& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.




// miscellaneous:

void clear(mat_GF2E& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_GF2E& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_GF2E operator+(const mat_GF2E& a, const mat_GF2E& b);
mat_GF2E operator-(const mat_GF2E& a, const mat_GF2E& b);
mat_GF2E operator*(const mat_GF2E& a, const mat_GF2E& b);

mat_GF2E operator-(const mat_GF2E& a);


// matrix/scalar multiplication:

mat_GF2E operator*(const mat_GF2E& a, const GF2E& b);
mat_GF2E operator*(const mat_GF2E& a, GF2 b);
mat_GF2E operator*(const mat_GF2E& a, long b);

mat_GF2E operator*(const GF2E& a, const mat_GF2E& b);
mat_GF2E operator*(GF2 a, const mat_GF2E& b);
mat_GF2E operator*(long a, const mat_GF2E& b);

// matrix/vector multiplication:

vec_GF2E operator*(const mat_GF2E& a, const vec_GF2E& b);

vec_GF2E operator*(const vec_GF2E& a, const mat_GF2E& b);


// assignment operator notation:

mat_GF2E& operator+=(mat_GF2E& x, const mat_GF2E& a);
mat_GF2E& operator-=(mat_GF2E& x, const mat_GF2E& a);
mat_GF2E& operator*=(mat_GF2E& x, const mat_GF2E& a);

mat_GF2E& operator*=(mat_GF2E& x, const GF2E& a);
mat_GF2E& operator*=(mat_GF2E& x, GF2 a);
mat_GF2E& operator*=(mat_GF2E& x, long a);

vec_GF2E& operator*=(vec_GF2E& x, const mat_GF2E& a);


ntl-11.5.1/doc/mat_RR.cpp.html0000644417616742025610000002163314064716023017563 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_RR.cpp.html

/**************************************************************************\

MODULE: mat_RR

SUMMARY:

Defines the class mat_RR.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_RR.h>

typedef Mat<RR> mat_RR; // backward compatibility

void add(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A + B

void sub(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A - B

void negate(mat_RR& X, const mat_RR& A);
// X = - A

void mul(mat_RR& X, const mat_RR& A, const mat_RR& B);
// X = A * B

void mul(vec_RR& x, const mat_RR& A, const vec_RR& b);
// x = A * b

void mul(vec_RR& x, const vec_RR& a, const mat_RR& B);
// x = a * B

void mul(mat_RR& X, const mat_RR& A, const RR& b);
void mul(mat_RR& X, const mat_RR& A, double b);
// X = A * b

void mul(mat_RR& X, const RR& a, const mat_RR& B);
void mul(mat_RR& X, double a, const mat_RR& B);
// X = a * B


void determinant(RR& d, const mat_RR& A);
RR determinant(const mat_RR& A);
// d = determinant(A)


void transpose(mat_RR& X, const mat_RR& A);
mat_RR transpose(const mat_RR& A);
// X = transpose of A

void solve(RR& d, vec_RR& X,
           const mat_RR& A, const vec_RR& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void inv(RR& d, mat_RR& X, const mat_RR& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_RR& X, const mat_RR& A);
mat_RR sqr(const mat_RR& A);
// X = A*A

void inv(mat_RR& X, const mat_RR& A);
mat_RR inv(const mat_RR& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_RR& X, const mat_RR& A, const ZZ& e);
mat_RR power(const mat_RR& A, const ZZ& e);

void power(mat_RR& X, const mat_RR& A, long e);
mat_RR power(const mat_RR& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_RR& X, long n);
mat_RR ident_mat_RR(long n);
// X = n x n identity matrix

long IsIdent(const mat_RR& A, long n);
// test if A is the n x n identity matrix

void diag(mat_RR& X, long n, const RR& d);
mat_RR diag(long n, const RR& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_RR& A, long n, const RR& d);
// test if X is an  n x n diagonal matrix with d on diagonal





// miscellaneous:

void clear(mat_RR& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_RR& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_RR operator+(const mat_RR& a, const mat_RR& b);
mat_RR operator-(const mat_RR& a, const mat_RR& b);
mat_RR operator*(const mat_RR& a, const mat_RR& b);

mat_RR operator-(const mat_RR& a);


// matrix/scalar multiplication:

mat_RR operator*(const mat_RR& a, const RR& b);
mat_RR operator*(const mat_RR& a, double b);

mat_RR operator*(const RR& a, const mat_RR& b);
mat_RR operator*(double a, const mat_RR& b);


// matrix/vector multiplication:

vec_RR operator*(const mat_RR& a, const vec_RR& b);

vec_RR operator*(const vec_RR& a, const mat_RR& b);


// assignment operator notation:

mat_RR& operator+=(mat_RR& x, const mat_RR& a);
mat_RR& operator-=(mat_RR& x, const mat_RR& a);
mat_RR& operator*=(mat_RR& x, const mat_RR& a);

mat_RR& operator*=(mat_RR& x, const RR& a);
mat_RR& operator*=(mat_RR& x, double a);

vec_RR& operator*=(vec_RR& x, const mat_RR& a);



ntl-11.5.1/doc/mat_ZZ.cpp.html0000644417616742025610000002646714064716023017615 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_ZZ.cpp.html

/**************************************************************************\

MODULE: mat_ZZ

SUMMARY:

Defines the class mat_ZZ.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ.h>

typedef Mat<ZZ> mat_ZZ; // backward compatibility

void add(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A + B

void sub(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A - B

void negate(mat_ZZ& X, const mat_ZZ& A);
// X = - A

void mul(mat_ZZ& X, const mat_ZZ& A, const mat_ZZ& B);
// X = A * B

void mul(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b);
// x = A * b

void mul(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B);
// x = a * B

void mul(mat_ZZ& X, const mat_ZZ& A, const ZZ& b);
void mul(mat_ZZ& X, const mat_ZZ& A, long b);
// X = A * b

void mul(mat_ZZ& X, const ZZ& a, const mat_ZZ& B);
void mul(mat_ZZ& X, long a, const mat_ZZ& B);
// X = a * B



void determinant(ZZ& d, const mat_ZZ& A, long deterministic=0);
ZZ determinant(const mat_ZZ& a, long deterministic=0);
// d = determinant(A).  If !deterministic, a randomized strategy may
// be used that errs with probability at most 2^{-80}.



void solve(ZZ& d, vec_ZZ& x,
           const mat_ZZ& A, const vec_ZZ& b,
           long deterministic=0)
// computes d = determinant(A) and solves x*A = b*d if d != 0; A must
// be a square matrix and have compatible dimensions with b.  If
// !deterministic, the computation of d may use a randomized strategy
// that errs with probability 2^{-80}.



void solve1(ZZ& d, vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b);
// A must be a square matrix.
// If A is singular, this routine sets d = 0 and returns.
// Otherwise, it computes d, x such that x*A == b*d, 
// such that d > 0 and minimal.
// Note that d is a positive divisor of the determinant,
// and is not in general equal to the determinant.
// The routine is deterministic, and uses a Hensel lifting strategy.

// For backward compatability, there is also a routine called
// HenselSolve1 that simply calls solve1.


void inv(ZZ& d, mat_ZZ& X, const mat_ZZ& A, long deterministic=0);
// computes d = determinant(A) and solves X*A = I*d if d != 0; A must
// be a square matrix.  If !deterministic, the computation of d may
// use a randomized strategy that errs with probability 2^{-80}.


// NOTE:  See LLL.txt for routines that compute the kernel and
// image of an integer matrix.

// NOTE: See HNF.txt for a routine that computes Hermite Normal Forms.

void sqr(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ sqr(const mat_ZZ& A);
// X = A*A   

void inv(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ inv(const mat_ZZ& A);
// X = A^{-1}; error is raised if |det(A)| != 1.

void power(mat_ZZ& X, const mat_ZZ& A, const ZZ& e);
mat_ZZ power(const mat_ZZ& A, const ZZ& e);

void power(mat_ZZ& X, const mat_ZZ& A, long e);
mat_ZZ power(const mat_ZZ& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).



void ident(mat_ZZ& X, long n);
mat_ZZ ident_mat_ZZ(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ& X, long n, const ZZ& d);
mat_ZZ diag(long n, const ZZ& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ& A, long n, const ZZ& d);
// test if X is an  n x n diagonal matrix with d on diagonal


void transpose(mat_ZZ& X, const mat_ZZ& A);
mat_ZZ transpose(const mat_ZZ& A);
// X = transpose of A


long CRT(mat_ZZ& a, ZZ& prod, const mat_zz_p& A);
// Incremental Chinese Remaindering: If p is the current zz_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.



// miscellaneous:

void clear(mat_ZZ& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ operator+(const mat_ZZ& a, const mat_ZZ& b);
mat_ZZ operator-(const mat_ZZ& a, const mat_ZZ& b);
mat_ZZ operator*(const mat_ZZ& a, const mat_ZZ& b);

mat_ZZ operator-(const mat_ZZ& a);


// matrix/scalar multiplication:

mat_ZZ operator*(const mat_ZZ& a, const ZZ& b);
mat_ZZ operator*(const mat_ZZ& a, long b);

mat_ZZ operator*(const ZZ& a, const mat_ZZ& b);
mat_ZZ operator*(long a, const mat_ZZ& b);

// matrix/vector multiplication:

vec_ZZ operator*(const mat_ZZ& a, const vec_ZZ& b);

vec_ZZ operator*(const vec_ZZ& a, const mat_ZZ& b);



// assignment operator notation:

mat_ZZ& operator+=(mat_ZZ& x, const mat_ZZ& a);
mat_ZZ& operator-=(mat_ZZ& x, const mat_ZZ& a);
mat_ZZ& operator*=(mat_ZZ& x, const mat_ZZ& a);

mat_ZZ& operator*=(mat_ZZ& x, const ZZ& a);
mat_ZZ& operator*=(mat_ZZ& x, long a);

vec_ZZ& operator*=(vec_ZZ& x, const mat_ZZ& a);


ntl-11.5.1/doc/mat_ZZ_p.cpp.html0000644417616742025610000002536314064716023020126 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_ZZ_p.cpp.html

/**************************************************************************\

MODULE: mat_ZZ_p

SUMMARY:

Defines the class mat_ZZ_p.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ_p.h>


typedef Mat<ZZ_p> mat_ZZ_p; // backward compatibility

void add(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A + B

void sub(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A - B

void negate(mat_ZZ_p& X, const mat_ZZ_p& A);
// X = - A

void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const mat_ZZ_p& B);
// X = A * B

void mul(vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b);
// x = A * b

void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const mat_ZZ_p& B);
// x = a * B

void mul(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ_p& b);
void mul(mat_ZZ_p& X, const mat_ZZ_p& A, long b);
// X = A * b

void mul(mat_ZZ_p& X, const ZZ_p& a, const mat_ZZ_p& B);
void mul(mat_ZZ_p& X, long a, const mat_ZZ_p& B);
// X = a * B


void determinant(ZZ_p& d, const mat_ZZ_p& A);
ZZ_p determinant(const mat_ZZ_p& a);
// d = determinant(A)


void transpose(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p transpose(const mat_ZZ_p& A);
// X = transpose of A

void solve(ZZ_p& d, vec_ZZ_p& x, const mat_ZZ_p& A, const vec_ZZ_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves x*A = b.

void solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p sqr(const mat_ZZ_p& A);
// X = A*A   

void inv(mat_ZZ_p& X, const mat_ZZ_p& A);
mat_ZZ_p inv(const mat_ZZ_p& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_ZZ_p& X, const mat_ZZ_p& A, const ZZ& e);
mat_ZZ_p power(const mat_ZZ_p& A, const ZZ& e);

void power(mat_ZZ_p& X, const mat_ZZ_p& A, long e);
mat_ZZ_p power(const mat_ZZ_p& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_ZZ_p& X, long n);
mat_ZZ_p ident_mat_ZZ_p(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ_p& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ_p& X, long n, const ZZ_p& d);
mat_ZZ_p diag(long n, const ZZ_p& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ_p& A, long n, const ZZ_p& d);
// test if X is an  n x n diagonal matrix with d on diagonal



void random(mat_ZZ_p& x, long n, long m);  // x = random n x m matrix
mat_ZZ_p random_mat_ZZ_p(long n, long m);



long gauss(mat_ZZ_p& M);
long gauss(mat_ZZ_p& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_ZZ_p& X, const mat_ZZ_p& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_ZZ_p& X, const mat_ZZ_p& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_ZZ_p& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ_p& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ_p operator+(const mat_ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator-(const mat_ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator*(const mat_ZZ_p& a, const mat_ZZ_p& b);

mat_ZZ_p operator-(const mat_ZZ_p& a);


// matrix/scalar multiplication:

mat_ZZ_p operator*(const mat_ZZ_p& a, const ZZ_p& b);
mat_ZZ_p operator*(const mat_ZZ_p& a, long b);

mat_ZZ_p operator*(const ZZ_p& a, const mat_ZZ_p& b);
mat_ZZ_p operator*(long a, const mat_ZZ_p& b);

// matrix/vector multiplication:

vec_ZZ_p operator*(const mat_ZZ_p& a, const vec_ZZ_p& b);

vec_ZZ_p operator*(const vec_ZZ_p& a, const mat_ZZ_p& b);


// assignment operator notation:

mat_ZZ_p& operator+=(mat_ZZ_p& x, const mat_ZZ_p& a);
mat_ZZ_p& operator-=(mat_ZZ_p& x, const mat_ZZ_p& a);
mat_ZZ_p& operator*=(mat_ZZ_p& x, const mat_ZZ_p& a);

mat_ZZ_p& operator*=(mat_ZZ_p& x, const ZZ_p& a);
mat_ZZ_p& operator*=(mat_ZZ_p& x, long a);

vec_ZZ_p& operator*=(vec_ZZ_p& x, const mat_ZZ_p& a);



ntl-11.5.1/doc/mat_ZZ_pE.cpp.html0000644417616742025610000002710114064716023020223 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_ZZ_pE.cpp.html

/**************************************************************************\

MODULE: mat_ZZ_pE

SUMMARY:

Defines the class mat_ZZ_pE.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_ZZ_pE.h>


typedef Mat<ZZ_pE> mat_ZZ_pE; // backward compatibility

void add(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A + B

void sub(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A - B

void negate(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// X = - A

void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const mat_ZZ_pE& B);
// X = A * B

void mul(vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b);
// x = A * b

void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const mat_ZZ_pE& B);
// x = a * B

void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_pE& b);
void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ_p& b);
void mul(mat_ZZ_pE& X, const mat_ZZ_pE& A, long b);
// X = A * b

void mul(mat_ZZ_pE& X, const ZZ_pE& a, const mat_ZZ_pE& B);
void mul(mat_ZZ_pE& X, const ZZ_p& a, const mat_ZZ_pE& B);
void mul(mat_ZZ_pE& X, long a, const mat_ZZ_pE& B);
// X = a * B


void determinant(ZZ_pE& d, const mat_ZZ_pE& A);
ZZ_pE determinant(const mat_ZZ_pE& a);
// d = determinant(A)


void transpose(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE transpose(const mat_ZZ_pE& A);
// X = transpose of A

void solve(ZZ_pE& d, vec_ZZ_pE& x, const mat_ZZ_pE& A, const vec_ZZ_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves x*A = b.

void solve(ZZ_pE& d, const mat_ZZ_pE& A, vec_ZZ_pE& x, const vec_ZZ_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(ZZ_pE& d, mat_ZZ_pE& X, const mat_ZZ_pE& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE sqr(const mat_ZZ_pE& A);
// X = A*A   

void inv(mat_ZZ_pE& X, const mat_ZZ_pE& A);
mat_ZZ_pE inv(const mat_ZZ_pE& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, const ZZ& e);
mat_ZZ_pE power(const mat_ZZ_pE& A, const ZZ& e);

void power(mat_ZZ_pE& X, const mat_ZZ_pE& A, long e);
mat_ZZ_pE power(const mat_ZZ_pE& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_ZZ_pE& X, long n);
mat_ZZ_pE ident_mat_ZZ_pE(long n);
// X = n x n identity matrix

long IsIdent(const mat_ZZ_pE& A, long n);
// test if A is the n x n identity matrix

void diag(mat_ZZ_pE& X, long n, const ZZ_pE& d);
mat_ZZ_pE diag(long n, const ZZ_pE& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_ZZ_pE& A, long n, const ZZ_pE& d);
// test if X is an  n x n diagonal matrix with d on diagonal


void random(mat_ZZ_pE& x, long n, long m);  // x = random n x m matrix
mat_ZZ_pE random_mat_ZZ_pE(long n, long m);




long gauss(mat_ZZ_pE& M);
long gauss(mat_ZZ_pE& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_ZZ_pE& X, const mat_ZZ_pE& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_ZZ_pE& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_ZZ_pE& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_ZZ_pE operator+(const mat_ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator-(const mat_ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, const mat_ZZ_pE& b);

mat_ZZ_pE operator-(const mat_ZZ_pE& a);


// matrix/scalar multiplication:

mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_pE& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, const ZZ_p& b);
mat_ZZ_pE operator*(const mat_ZZ_pE& a, long b);

mat_ZZ_pE operator*(const ZZ_pE& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(const ZZ_p& a, const mat_ZZ_pE& b);
mat_ZZ_pE operator*(long a, const mat_ZZ_pE& b);

// matrix/vector multiplication:

vec_ZZ_pE operator*(const mat_ZZ_pE& a, const vec_ZZ_pE& b);

vec_ZZ_pE operator*(const vec_ZZ_pE& a, const mat_ZZ_pE& b);


// assignment operator notation:

mat_ZZ_pE& operator+=(mat_ZZ_pE& x, const mat_ZZ_pE& a);
mat_ZZ_pE& operator-=(mat_ZZ_pE& x, const mat_ZZ_pE& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const mat_ZZ_pE& a);

mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_pE& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, const ZZ_p& a);
mat_ZZ_pE& operator*=(mat_ZZ_pE& x, long a);

vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const mat_ZZ_pE& a);



ntl-11.5.1/doc/mat_lzz_p.cpp.html0000644417616742025610000003631114064716023020375 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_lzz_p.cpp.html

/**************************************************************************\

MODULE: mat_zz_p

SUMMARY:

Defines the class mat_zz_p.
Note that the modulus p need not be a prime, except as indicated below.

IMPLEMENTATION NOTES: 

Starting with NTL version 9.7.0 (and 9.7.1), many of the routines here have
been optimized to take better advantage of specific hardware features available
on 64-bit Intel CPU's.  Currently, the mul, inv, determinant, solve, gauss,
kernel, and image routines are fastest for p up to 23-bits long (assuming the
CPU supports AVX instructions).  After that, performance degrades in three
stages: stage 1: up to 28-bits; stage 2: up to 31-bits; stage 3: 32-bits and
up. 

For primes up to 23-bits, AVX floating point instructions are used.  After
that, ordinary integer arithmetic is used.  In a future version, I may exploit
AVX2 integer instructions to get better stage 2 performance.  And in the more
distant future, AVX512 instructions will be used, when they become available.

On older Intel machines, or non-Intel machines that have "long long" support,
one still gets optimizations corresponding to the three stages above.  On
32-bit machines, one still gets three stages, just with smaller crossover
points.

\**************************************************************************/


#include <NTL/matrix.h>
#include "vec_vec_zz_p.h"


typedef Mat<zz_p> mat_zz_p; // backward compatibility

void add(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A + B

void sub(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A - B

void mul(mat_zz_p& X, const mat_zz_p& A, const mat_zz_p& B);
// X = A * B

void mul(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b);
// x = A * b

void mul(vec_zz_p& x, const vec_zz_p& a, const mat_zz_p& B);
// x = a * B

void mul(mat_zz_p& X, const mat_zz_p& A, zz_p b);
void mul(mat_zz_p& X, const mat_zz_p& A, long b);
// X = A * b

void mul(mat_zz_p& X, zz_p a, const mat_zz_p& B);
void mul(mat_zz_p& X, long a, const mat_zz_p& B);
// X = a * B


void transpose(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p transpose(const mat_zz_p& A);
// X = transpose of A


void determinant(zz_p& d, const mat_zz_p& A);
zz_p determinant(const mat_zz_p& a);
// d = determinant(A)

void solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves x*A = b (so x and b are treated as a row vectors).

void solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.


void inv(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p inv(const mat_zz_p& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e);
mat_zz_p power(const mat_zz_p& A, const ZZ& e);
void power(mat_zz_p& X, const mat_zz_p& A, long e);
mat_zz_p power(const mat_zz_p& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

// NOTE: the routines determinant, solve, inv, and power (with negative
// exponent) all require that the modulus p is prime: during elimination, if a
// non-zero pivot element does not have an inverse, and error is raised.  The
// following "relaxed" versions of these routines will also work with prime
// powers, if the optional parameter relax is true (which is the default).
// However, note that in these relaxed routines, if a computed determinant
// value is zero, this may not be the true determinant: all that you can assume
// is that the true determinant is not invertible mod p. If the parameter
// relax==false, then these routines behave identically to their "unrelaxed"
// counterparts.

void relaxed_determinant(zz_p& d, const mat_zz_p& A, bool relax=true);
zz_p relaxed_determinant(const mat_zz_p& a, bool relax=true);
void relaxed_solve(zz_p& d, vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b, bool relax=true);
void relaxed_solve(zz_p& d, const mat_zz_p& A, vec_zz_p& x, const vec_zz_p& b, bool relax=true);
void relaxed_inv(zz_p& d, mat_zz_p& X, const mat_zz_p& A, bool relax=true);
void relaxed_inv(mat_zz_p& X, const mat_zz_p& A, bool relax=true);
mat_zz_p relaxed_inv(const mat_zz_p& A, bool relax=true);
void relaxed_power(mat_zz_p& X, const mat_zz_p& A, const ZZ& e, bool relax=true);
mat_zz_p relaxed_power(const mat_zz_p& A, const ZZ& e, bool relax=true);
void relaxed_power(mat_zz_p& X, const mat_zz_p& A, long e, bool relax=true);
mat_zz_p relaxed_power(const mat_zz_p& A, long e, bool relax=true);


void sqr(mat_zz_p& X, const mat_zz_p& A);
mat_zz_p sqr(const mat_zz_p& A);
// X = A*A   

void ident(mat_zz_p& X, long n);
mat_zz_p ident_mat_zz_p(long n);
// X = n x n identity matrix

long IsIdent(const mat_zz_p& A, long n);
// test if A is the n x n identity matrix

void diag(mat_zz_p& X, long n, zz_p d);
mat_zz_p diag(long n, zz_p d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_zz_p& A, long n, zz_p d);
// test if X is an  n x n diagonal matrix with d on diagonal


void random(mat_zz_p& x, long n, long m);  // x = random n x m matrix
mat_zz_p random_mat_zz_p(long n, long m);



long gauss(mat_zz_p& M);
long gauss(mat_zz_p& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_zz_p& X, const mat_zz_p& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_zz_p& X, const mat_zz_p& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.

// NOTE: the gauss, image, and kernel routines all require that
// the modulus p is prime. 



// miscellaneous:

void clear(mat_zz_p& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_zz_p& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_zz_p operator+(const mat_zz_p& a, const mat_zz_p& b);
mat_zz_p operator-(const mat_zz_p& a, const mat_zz_p& b);
mat_zz_p operator*(const mat_zz_p& a, const mat_zz_p& b);

mat_zz_p operator-(const mat_zz_p& a);


// matrix/scalar multiplication:

mat_zz_p operator*(const mat_zz_p& a, zz_p b);
mat_zz_p operator*(const mat_zz_p& a, long b);

mat_zz_p operator*(zz_p a, const mat_zz_p& b);
mat_zz_p operator*(long a, const mat_zz_p& b);


// matrix/vector multiplication:

vec_zz_p operator*(const mat_zz_p& a, const vec_zz_p& b);

vec_zz_p operator*(const vec_zz_p& a, const mat_zz_p& b);


// assignment operator notation:

mat_zz_p& operator+=(mat_zz_p& x, const mat_zz_p& a);
mat_zz_p& operator-=(mat_zz_p& x, const mat_zz_p& a);
mat_zz_p& operator*=(mat_zz_p& x, const mat_zz_p& a);

mat_zz_p& operator*=(mat_zz_p& x, zz_p a);
mat_zz_p& operator*=(mat_zz_p& x, long a);

vec_zz_p& operator*=(vec_zz_p& x, const mat_zz_p& a);


ntl-11.5.1/doc/mat_lzz_pE.cpp.html0000644417616742025610000002710414064716023020502 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_lzz_pE.cpp.html

/**************************************************************************\

MODULE: mat_zz_pE

SUMMARY:

Defines the class mat_zz_pE.

\**************************************************************************/


#include <NTL/matrix.h>
#include <NTL/vec_vec_lzz_pE.h>


typedef Mat<zz_pE> mat_zz_pE; // backward compatibility

void add(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A + B

void sub(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A - B

void negate(mat_zz_pE& X, const mat_zz_pE& A);
// X = - A

void mul(mat_zz_pE& X, const mat_zz_pE& A, const mat_zz_pE& B);
// X = A * B

void mul(vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b);
// x = A * b

void mul(vec_zz_pE& x, const vec_zz_pE& a, const mat_zz_pE& B);
// x = a * B

void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_pE& b);
void mul(mat_zz_pE& X, const mat_zz_pE& A, const zz_p& b);
void mul(mat_zz_pE& X, const mat_zz_pE& A, long b);
// X = A * b

void mul(mat_zz_pE& X, const zz_pE& a, const mat_zz_pE& B);
void mul(mat_zz_pE& X, const zz_p& a, const mat_zz_pE& B);
void mul(mat_zz_pE& X, long a, const mat_zz_pE& B);
// X = a * B


void determinant(zz_pE& d, const mat_zz_pE& A);
zz_pE determinant(const mat_zz_pE& a);
// d = determinant(A)


void transpose(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE transpose(const mat_zz_pE& A);
// X = transpose of A

void solve(zz_pE& d, vec_zz_pE& x, const mat_zz_pE& A, const vec_zz_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d =
// determinant(A).  If d != 0, solves x*A = b.

void solve(zz_pE& d, const mat_zz_pE& A, vec_zz_pE& x, const vec_zz_pE& b);
// A is an n x n matrix, b is a length n vector.  Computes d = determinant(A).
// If d != 0, solves A*x = b (so x and b are treated as a column vectors).

void inv(zz_pE& d, mat_zz_pE& X, const mat_zz_pE& A);
// A is an n x n matrix.  Computes d = determinant(A).  If d != 0,
// computes X = A^{-1}.

void sqr(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE sqr(const mat_zz_pE& A);
// X = A*A   

void inv(mat_zz_pE& X, const mat_zz_pE& A);
mat_zz_pE inv(const mat_zz_pE& A);
// X = A^{-1}; error is raised if A is  singular

void power(mat_zz_pE& X, const mat_zz_pE& A, const ZZ& e);
mat_zz_pE power(const mat_zz_pE& A, const ZZ& e);

void power(mat_zz_pE& X, const mat_zz_pE& A, long e);
mat_zz_pE power(const mat_zz_pE& A, long e);
// X = A^e; e may be negative (in which case A must be nonsingular).

void ident(mat_zz_pE& X, long n);
mat_zz_pE ident_mat_zz_pE(long n);
// X = n x n identity matrix

long IsIdent(const mat_zz_pE& A, long n);
// test if A is the n x n identity matrix

void diag(mat_zz_pE& X, long n, const zz_pE& d);
mat_zz_pE diag(long n, const zz_pE& d);
// X = n x n diagonal matrix with d on diagonal

long IsDiag(const mat_zz_pE& A, long n, const zz_pE& d);
// test if X is an  n x n diagonal matrix with d on diagonal


void random(mat_zz_pE& x, long n, long m);  // x = random n x m matrix
mat_zz_pE random_mat_zz_pE(long n, long m);




long gauss(mat_zz_pE& M);
long gauss(mat_zz_pE& M, long w);
// Performs unitary row operations so as to bring M into row echelon
// form.  If the optional argument w is supplied, stops when first w
// columns are in echelon form.  The return value is the rank (or the
// rank of the first w columns).

void image(mat_zz_pE& X, const mat_zz_pE& A);
// The rows of X are computed as basis of A's row space.  X is is row
// echelon form

void kernel(mat_zz_pE& X, const mat_zz_pE& A);
// Computes a basis for the kernel of the map x -> x*A. where x is a
// row vector.



// miscellaneous:

void clear(mat_zz_pE& a);
// x = 0 (dimension unchanged)

long IsZero(const mat_zz_pE& a);
// test if a is the zero matrix (any dimension)


// operator notation:

mat_zz_pE operator+(const mat_zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator-(const mat_zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator*(const mat_zz_pE& a, const mat_zz_pE& b);

mat_zz_pE operator-(const mat_zz_pE& a);


// matrix/scalar multiplication:

mat_zz_pE operator*(const mat_zz_pE& a, const zz_pE& b);
mat_zz_pE operator*(const mat_zz_pE& a, const zz_p& b);
mat_zz_pE operator*(const mat_zz_pE& a, long b);

mat_zz_pE operator*(const zz_pE& a, const mat_zz_pE& b);
mat_zz_pE operator*(const zz_p& a, const mat_zz_pE& b);
mat_zz_pE operator*(long a, const mat_zz_pE& b);

// matrix/vector multiplication:

vec_zz_pE operator*(const mat_zz_pE& a, const vec_zz_pE& b);

vec_zz_pE operator*(const vec_zz_pE& a, const mat_zz_pE& b);


// assignment operator notation:

mat_zz_pE& operator+=(mat_zz_pE& x, const mat_zz_pE& a);
mat_zz_pE& operator-=(mat_zz_pE& x, const mat_zz_pE& a);
mat_zz_pE& operator*=(mat_zz_pE& x, const mat_zz_pE& a);

mat_zz_pE& operator*=(mat_zz_pE& x, const zz_pE& a);
mat_zz_pE& operator*=(mat_zz_pE& x, const zz_p& a);
mat_zz_pE& operator*=(mat_zz_pE& x, long a);

vec_zz_pE& operator*=(vec_zz_pE& x, const mat_zz_pE& a);



ntl-11.5.1/doc/mat_poly_ZZ.cpp.html0000644417616742025610000000345614064716023020651 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_poly_ZZ.cpp.html

/**************************************************************************\

MODULE: mat_poly_ZZ

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over ZZ.



\**************************************************************************/


#include <NTL/mat_ZZ.h>
#include <NTL/ZZX.h>

void CharPoly(ZZX& f, const mat_ZZ& M);
// f = characteristic polynomial of M


ntl-11.5.1/doc/mat_poly_ZZ_p.cpp.html0000644417616742025610000000350114064716023021157 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_poly_ZZ_p.cpp.html

/*****************************************************************************\

MODULE: mat_poly_ZZ_p

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over ZZ_p.



\*****************************************************************************/


#include <NTL/mat_ZZ_p.h>
#include <NTL/ZZ_pX.h>

void CharPoly(ZZ_pX& f, const mat_ZZ_p& M);
// f = characteristic polynomial of M

ntl-11.5.1/doc/mat_poly_lzz_p.cpp.html0000644417616742025610000000347514064716023021445 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/mat_poly_lzz_p.cpp.html

/**************************************************************************\

MODULE: mat_poly_zz_p

SUMMARY:

Routine for computing the characteristic polynomial of a matrix over zz_p.



\**************************************************************************/


#include "mat_zz_p.h"
#include "zz_pX.h"

void CharPoly(zz_pX& f, const mat_zz_p& M);
// f = characteristic polynomial of M


ntl-11.5.1/doc/matrix.cpp.html0000644417616742025610000002764714064716023017716 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/matrix.cpp.html

/**************************************************************************\

MODULE: matrix

SUMMARY:

Matrix templates.

The declaration 

   Mat<T> M;

creates a 0 x 0 matrix.  

We can make it have 10 rows and 20 columns like this:

   M.SetDims(10, 20);

A row can be accessed as M[i], indexing from 0, or as M(i), indexing from 1.
A matrix entry can be accessed as M[i][j], indexing from 0, or as
M(i, j), indexing from 1.

A matrix is represented as a Vec< Vec<T> >: a vector of rows, where
each row is a Vec<T>.  Any attempt to resize one of the rows so
as to create a non-rectangular matrix will result in a run-time 
error.

The dimensions of an existing matrix may be changed.  If the number of
columns does not change, then the matrix is just "resized" like a vector,
and no information is lost.  Otherwise, if the number of columns changes,
the matrix is completely destroyed, and a new matrix is created


\**************************************************************************/


// EXCEPTIONS: all functions below do not throw any exceptions,
//   except as noted

template<class T>
class Mat {

   typedef typename Vec<T>::value_type value_type;
   typedef typename Vec<T>::reference reference;
   typedef typename Vec<T>::const_reference const_reference;


   Mat(); // initially 0 x 0

   Mat(const Mat<T>& a);
   // copy constructor

   // EXCEPTIONS: may throw


   Mat& operator=(const Mat<T>& a);
   // assignment

   // EXCEPTIONS: may throw, weak ES (but dimensions of LHS
   //   will be either that of old LHS or RHS)

   ~Mat();
   // destructor

   Mat(Mat&& other) noexcept;
#ifndef NTL_DISABLE_MOVE_ASSIGN
   Mat& operator=(Mat&& other) noexcept;
#endif
   // move semantics (C++11 only)

   Mat(INIT_SIZE_TYPE, long n, long m);
   // Mat(INIT_SIZE, n, m) initializes an n x m matrix, invoking
   // the default constructor for T to initialize entries.

   // EXCEPTIONS: may throw

   void SetDims(long n, long m);
   // M.SetDims(n, m) makes M have dimension n x m.  If the number of
   // columns (m) changes, previous storage is freed, and space for M
   // is reallocated and initialized; otherwise, more rows are
   // allocated as necessary (when number of rows increases), 
   // excess rows are retained (when number of rows decreases),
   // and--importantly--the contents do not change.

   // EXCEPTIONS: strong ES (although underlying vector representation
   //    may be reallocated)

   void kill(); free storage and make 0 x 0

   long NumRows() const;
   // M.NumRows() returns the number of rows of M

   long NumCols() const;
   // M.NumCols() returns the number of columns of M

   Vec<T>& operator[](long i);
   const Vec<T>& operator[](long i) const;
   // access row i, initial index 0.  
   // Even if one has read/write access to a row, any attempt
   // to change its length will raise an error.

   // EXCEPTIONS: may throw if range checking is turned on

   Vec<T>& operator()(long i);
   const Vec<T>& operator()(long i) const;
   // access row i, initial index 1. 
   // Even if one has read/write access to a row, any attempt
   // to change its length will raise an error.
   // of this row will raise an error.

   // EXCEPTIONS: may throw if range checking is turned on

   reference operator()(long i, long j);
   const_reference operator()(long i, long j) const;
   // access element (i, j), both indices starting at 1

   // EXCEPTIONS: may throw if range checking is turned on

   const_reference get(long i, long j) const;
   // access element (i, j), both indices starting at 0

   // EXCEPTIONS: may throw if range checking is turned on

   void put(long i, long j, const T& a);
   // same as M[i].put(j, a)

   template <class U>
   void put(long i, long j, const U& a);
   // same as M[i].put(j, a)

   long position(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position(a).

   long position1(const Vec<T>& a) const;
   // returns index of a in matrix, or -1 if not present;
   // equivalent to rep(*this).position1(a).

   long alias(const Vec<T>& a) const;
   // returns 1 if a aliases a row of the matrix, and 0 otherwise.

   void swap(Mat<T>& other);
   // quick swap *this and other

   void move(Mat<T>& other);
   // quick move other to *this

};

template<class T>
const Vec< Vec<T> >& rep(const Mat<T>& a);
// read-only access to underlying representation

template<class T>
void swap(Mat<T>& X, Mat<T>& Y);
// quick swap of X and Y 

template<class T>
void MakeMatrix(Mat<T>& x, const vec_vec_T& a);
// copies a to x, checking that it is "rectangular"

// EXCEPTIONS: may thow, weak ES (but dimensions of x either
//    remain unchanged or are set to the new dimensions implied by a)

/**************************************************************************\

                            Input/Output

\**************************************************************************/


template<class T>
istream& operator>>(istream&, Mat<T>&);

// EXCEPTIONS: may throw, weak ES

template<class T>
ostream& operator<<(ostream&, const Mat<T>&);

// EXCEPTIONS: may throw, weak ES


/**************************************************************************\

                              Equality Testing


\**************************************************************************/


template<class T>
long operator==(const Mat<T>& a, const Mat<T>& b);

template<class T>
long operator!=(const Mat<T>& a, const Mat<T>& b);

ntl-11.5.1/doc/pair.cpp.html0000644417616742025610000001112714064716023017327 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/pair.cpp.html
/**************************************************************************\

MODULE: pair

SUMMARY:

Pair templates.

The decalaration 

   Pair<S,T> p;

creates a pair object using the default constructors for S and T.  The
member p.a is the first component (of type S) and the member p.b is
the second component (of type T).


\**************************************************************************/



#include <NTL/tools.h>

template<class S, class T>
class Pair {
public:
   S a;
   T b;

   Pair();
   // default constructor...invokes default constructors for S and T

   Pair(const S& x, const T& y);  // initialize with (x, y)

   ~Pair();
   // destructor...invokes destructors for S and T

   // defaut copy and move constructors and assignment 
};

template<class S, class T>
Pair<S,T> cons(const S& x, const T& y);
// returns Pair<S,T>(x, y)


/**************************************************************************\

                             Input/Output

The I/O format for a Pair is

   [a b]

\**************************************************************************/


template<class S, class T>
istream& operator>>(istream&, Pair<S,T>&);

template<class S, class T>
ostream& operator<<(ostream&, const Pair<S,T>&);


/**************************************************************************\

                              Equality Testing

\**************************************************************************/


template<class S, class T>
long operator==(const Pair<S,T>& x, const Pair<S,T>& y);

template<class S, class T>
long operator!=(const Pair<S,T>& x, const Pair<S,T>& y);


ntl-11.5.1/doc/quad_float.cpp.html0000644417616742025610000006052614064716023020522 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/quad_float.cpp.html


/**************************************************************************\

MODULE: quad_float

SUMMARY:

The class quad_float is used to represent quadruple precision numbers.
Thus, with standard IEEE floating point, you should get the equivalent
of about 106 bits of precision (but actually just a bit less).

The interface allows you to treat quad_floats more or less as if they were
"ordinary" floating point types.

See below for more implementation details.


\**************************************************************************/

#include <NTL/ZZ.h>


class quad_float {
public:

quad_float(); // = 0

quad_float(const quad_float& a);  // copy constructor

explicit quad_float(double a);  // promotion constructor


quad_float& operator=(const quad_float& a);  // assignment operator
quad_float& operator=(double a);

~quad_float();


static void SetOutputPrecision(long p);
// This sets the number of decimal digits to be output.  Default is
// 10.


static long OutputPrecision();
// returns current output precision.


};


/**************************************************************************\

                             Arithmetic Operations

\**************************************************************************/




quad_float operator +(const quad_float& x, const quad_float& y);
quad_float operator -(const quad_float& x, const quad_float& y);
quad_float operator *(const quad_float& x, const quad_float& y);
quad_float operator /(const quad_float& x, const quad_float& y);


// PROMOTIONS: operators +, -, *, / promote double to quad_float
// on (x, y).

quad_float operator -(const quad_float& x);

quad_float& operator += (quad_float& x, const quad_float& y);
quad_float& operator += (quad_float& x, double y);

quad_float& operator -= (quad_float& x, const quad_float& y);
quad_float& operator -= (quad_float& x, double y);

quad_float& operator *= (quad_float& x, const quad_float& y);
quad_float& operator *= (quad_float& x, double y);

quad_float& operator /= (quad_float& x, const quad_float& y);
quad_float& operator /= (quad_float& x, double y);

quad_float& operator++(quad_float& a); // prefix
void operator++(quad_float& a, int); // postfix

quad_float& operator--(quad_float& a); // prefix
void operator--(quad_float& a, int); // postfix



/**************************************************************************\

                                  Comparison

\**************************************************************************/


long operator> (const quad_float& x, const quad_float& y);
long operator>=(const quad_float& x, const quad_float& y);
long operator< (const quad_float& x, const quad_float& y);
long operator<=(const quad_float& x, const quad_float& y);
long operator==(const quad_float& x, const quad_float& y);
long operator!=(const quad_float& x, const quad_float& y);

long sign(const quad_float& x);  // sign of x, -1, 0, +1
long compare(const quad_float& x, const quad_float& y); // sign of x - y

// PROMOTIONS: operators >, ..., != and function compare
// promote double to quad_float on (x, y).


/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5  5.  -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine quad_float::SetOutputPrecision(p).  
The default value of p is 10.
The current value of p is returned by a call to quad_float::OutputPrecision().



\**************************************************************************/


istream& operator >> (istream& s, quad_float& x);
ostream& operator << (ostream& s, const quad_float& x);


/**************************************************************************\

                                  Miscellaneous

\**************************************************************************/



quad_float sqrt(const quad_float& x);
quad_float floor(const quad_float& x);
quad_float ceil(const quad_float& x);
quad_float trunc(const quad_float& x);
quad_float fabs(const quad_float& x);
quad_float exp(const quad_float& x);
quad_float log(const quad_float& x);


void power(quad_float& x, const quad_float& a, long e); // x = a^e
quad_float power(const quad_float& a, long e);

void power2(quad_float& x, long e); // x = 2^e
quad_float power2_quad_float(long e);

quad_float ldexp(const quad_float& x, long e);  // return x*2^e

long IsFinite(quad_float *x); // checks if x is "finite"   
                              // pointer is used for compatability with
                              // IsFinite(double*)


void random(quad_float& x);
quad_float random_quad_float();
// generate a random quad_float x with 0 <= x <= 1





/***********************************************************************\

IMPLEMENTATION DETAILS

A quad_float x is represented as a pair of doubles, x.hi and x.lo,
such that the number represented by x is x.hi + x.lo, where

   |x.lo| <= 0.5*ulp(x.hi),  (*)

and ulp(y) means "unit in the last place of y".  

For the software to work correctly, IEEE Standard Arithmetic is sufficient.  
However, there are a couple subtle points (see below).

This is a rather weird representation;  although it gives one
essentially twice the precision of an ordinary double, it is
not really the equivalent of quadratic precision (despite the name).
For example, the number 1 + 2^{-200} can be represented exactly as
a quad_float.  Also, there is no real notion of "machine precision".

Note that overflow/underflow for quad_floats does not follow any particularly
useful rules, even if the underlying floating point arithmetic is IEEE
compliant.  Generally, when an overflow/underflow occurs, the resulting value
is unpredicatble, although typically when overflow occurs in computing a value
x, the result is non-finite (i.e., IsFinite(&x) == 0).  Note, however, that
some care is taken to ensure that the ZZ to quad_float conversion routine
produces a non-finite value upon overflow.



THE EXTENDED PRECISION PROBLEM

Some machines may compute intermediate floating point results in an extended
double precision format.  The only machines I know that do this are old
(pre-SSE) x86 machines that rely on the x87 coprocessor instruction set, so
this is mainly of historical interest these days.  On these old machines,
intermediate results are stored in the 80-bit x87 floating point registers.
These registers have 53 or 64 bits of precision---this can be set at run-time
by modifying the cpu "control word" (either in assembly or through special
compiler intrinsics).  If the preicsion is set to 64 bits, the quad_float
routines will produce incorrect results.


The best way to fix this problem is to set the precsion of the x87 registers to
53 at the beginning of program execution and to leave it.  This is what Windows
with MSVC++ does.  On Linux with gcc (and other compilers), however, this is
not the case: the precision of the registers is set to 64 bits.

To fix this problem, the build process for NTL automatically checks for
extended double preceision, and if detected, arranges for the quad_float
routines to locally set the precision to 53 bits on entry and back to 64 bits
on exit.  This only works with GCC and GCC-compatible compilers (including
CLANG and ICC) that support GCC's inline assembly syntax.  The configuration
flags  NTL_FIX_X86 or NTL_NO_FIX_X86 can be set to override NTL's default
behavior (but I've never really seen a need to use them).

If all else fails, NTL will revert to a strategy of  forcing all intermediate
floating point results into memory.  This is not an ideal fix, since it is not
fully equivalent to 53-bit precision (because of double rounding), but it works
(although to be honest, I've never seen a full proof of correctness in this
case).  NTL's quad_float code does this by storing intermediate results in
local variables declared to be 'volatile'.  This is the solution to the problem
that NTL uses if it detects the problem and can't fix it using the control word
hack mentioned above.  In fact, I've never seen a platform where this strategy
is required.

To reiterate: this is all mainly of historical interest, as the x87 coprocessor
is pretty much not used any more.


THE FMA PROBLEM

Some CPUs come equipped with a fused-multiply-add (FMA) instruction, which
computes x + a*b with just a single rounding.  While this generally is faster
and more precise than performing this using two instructions and two roundings,
FMA instructions can break the logic of quad_float.  

To mitigate this problem, NTL's configuration script will attempt to detect the
existence of FMA's, and if detected, to supress them using a compiler flag.
Right now, NTL's configuration script only attempts to fix this problem for the
GCC, CLANG, and ICC compilers.  GCC,  this is done with the flag
-ffp-contract=off (or the flag -mno-fused-madd, which is obsolete in new
versions of GCC).  On CLANG, this is also done with the flag -ffp-contract=off,
although by default, CLANG will not emit FMA's, so this should not be
necessary.  On ICC, this is done by the fp_contract(off) pragma.  This is
accomplished by passing information through the make variable NOCONTRACT, which
is only used in the compilation of quad_float.cpp.



THE FLOATING POINT REASSOCIATION PROBLEM

The C++ standard says that compilers must issue instructions that respect the
grouping of floating point operations.  So the compiler is not allowed to
compile (a+b)+c as a+(b+c).  Most compilers repect this rule by default, but
some do not (such as Intel's ICC compiler).  The logic of quad_float relies
crucially on this rule.

In fact, NTL attempts to ensure that all of its source files get compiled with
this rule in force.  To this end, if the configuration script detects an ICC
compiler, it will pass the "-fp-model precise" flag through to the compiler
(via the CXXAUTOFLAGS make variable) when compiling *all* source files (not
just quad_float.cpp).


BACKGROUND INFO

The code NTL uses algorithms designed by Knuth, Kahan, Dekker, and
Linnainmaa.  The original transcription to C++ was done by Douglas
Priest.  Enhancements and bug fixes were done by Keith Briggs ---
see http://keithbriggs.info/doubledouble.html.  The NTL version is a
stripped down version of Briggs' code, with some bug fixes and
portability improvements.  

Here is a brief annotated bibliography (compiled by Priest) of papers 
dealing with DP and similar techniques, arranged chronologically.


Kahan, W., Further Remarks on Reducing Truncation Errors,
  {\it Comm.\ ACM\/} {\bf 8} (1965), 40.

M{\o}ller, O., Quasi Double Precision in Floating-Point Addition,
  {\it BIT\/} {\bf 5} (1965), 37--50.

  The two papers that first presented the idea of recovering the
  roundoff of a sum.

Dekker, T., A Floating-Point Technique for Extending the Available
  Precision, {\it Numer.\ Math.} {\bf 18} (1971), 224--242.

  The classic reference for DP algorithms for sum, product, quotient,
  and square root.

Pichat, M., Correction d'une Somme en Arithmetique \`a Virgule
  Flottante, {\it Numer.\ Math.} {\bf 19} (1972), 400--406.

  An iterative algorithm for computing a protracted sum to working
  precision by repeatedly applying the sum-and-roundoff method.

Linnainmaa, S., Analysis of Some Known Methods of Improving the Accuracy
  of Floating-Point Sums, {\it BIT\/} {\bf 14} (1974), 167--202.

  Comparison of Kahan and M{\o}ller algorithms with variations given
  by Knuth.

Bohlender, G., Floating-Point Computation of Functions with Maximum
  Accuracy, {\it IEEE Trans.\ Comput.} {\bf C-26} (1977), 621--632.

  Extended the analysis of Pichat's algorithm to compute a multi-word
  representation of the exact sum of n working precision numbers.
  This is the algorithm Kahan has called "distillation".

Linnainmaa, S., Software for Doubled-Precision Floating-Point Computations,
  {\it ACM Trans.\ Math.\ Soft.} {\bf 7} (1981), 272--283.

  Generalized the hypotheses of Dekker and showed how to take advantage
  of extended precision where available.

Leuprecht, H., and W.~Oberaigner, Parallel Algorithms for the Rounding-Exact
  Summation of Floating-Point Numbers, {\it Computing} {\bf 28} (1982), 89--104.

  Variations of distillation appropriate for parallel and vector
  architectures.

Kahan, W., Paradoxes in Concepts of Accuracy, lecture notes from Joint
  Seminar on Issues and Directions in Scientific Computation, Berkeley, 1989.

  Gives the more accurate DP sum I've shown above, discusses some
  examples.

Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic,
  in P.~Kornerup and D.~Matula, Eds., {\it Proc.\ 10th Symposium on Com-
  puter Arithmetic}, IEEE Computer Society Press, Los Alamitos, Calif., 1991.

  Extends from DP to arbitrary precision; gives portable algorithms and
  general proofs.

Sorensen, D., and P.~Tang, On the Orthogonality of Eigenvectors Computed
  by Divide-and-Conquer Techniques, {\it SIAM J.\ Num.\ Anal.} {\bf 28}
  (1991), 1752--1775.

  Uses some DP arithmetic to retain orthogonality of eigenvectors
  computed by a parallel divide-and-conquer scheme.

Priest, D., On Properties of Floating Point Arithmetics: Numerical Stability
  and the Cost of Accurate Computations, Ph.D. dissertation, University
  of California at Berkeley, 1992.

  More examples, organizes proofs in terms of common properties of fp
  addition/subtraction, gives other summation algorithms.

Another relevant paper: 

X. S. Li, et al.
Design, implementation, and testing of extended and mixed 
precision BLAS.  ACM Trans. Math. Soft., 28:152-205, 2002.



\***********************************************************************/

ntl-11.5.1/doc/tools.cpp.html0000644417616742025610000003355714064716023017547 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/tools.cpp.html

/**************************************************************************\

MODULE: tools

SUMMARY:

Some useful tools that are used throughout NTL.

\**************************************************************************/

#include <cstdlib>
#include <cmath>
#include <cstring>

#include <utility>
#include <iostream>
#include <new>
#include <stdexcept>

#include <NTL/config.h>
#include <NTL/mach_desc.h>




double GetTime();
// returns number of seconds of CPU time used by this process.

double GetWallTime();
// returns the "wall clock" time, measured since the beginning
// of some unspecified epoch.  This is useful for measuring the
// performance of multi-threaded code, since in this case,
// GetTime does not return very useful information in that case.

void PrintTime(ostream& s, double t);
// prints the time t (in seconds) to s in the format
//     ss  or  mm:ss  or  hh:mm:ss,
// where the value t is first rounded to the nearest integer.


long IsWhiteSpace(long c);
// returns 1 if c is "white space" (as defined by isspace is the
// standard library...usually blanks, tabs, newlines), and 0 otherwise.

long SkipWhiteSpace(istream& s);
// skips white space (as defined by IsWhiteSpace).
// Return value is 0 if end-of-file is reached; otherwise,
// return value is 1.


long IsEOFChar(long c);
// test if c == EOF


long CharToIntVal(long c);
// returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f';
// otherwise, the return value is -1.

char IntValToChar(long x);
// returns the hexadecimal digit '0'..'9', 'a'..'f' representing x;
// an error is raised if x < 0 or x > 15.

long IsFinite(double *p);
// Returns 1 if *p is a "finite" floating point number.
// A pointer is used to ensure that the number is in memory,
// which on some architectures (notably x86/Pentium) can make a difference.

// some min/max and swap routines:

int min(int a, int b);
int max(int a, int b);

long min(long a, long b);
long max(long a, long b);

long min(int a, long b);
long max(int a, long b);

long min(long a, int b);
long max(long a, int b);

unsigned int min(unsigned int a, unsigned int b);
unsigned int max(unsigned int a, unsigned int b);

unsigned long min(unsigned long a, unsigned long b);
unsigned long max(unsigned long a, unsigned long b);

unsigned long min(unsigned int a, unsigned long b);
unsigned long max(unsigned int a, unsigned long b);

unsigned long min(unsigned long a, unsigned int b);
unsigned long max(unsigned long a, unsigned int b);


void swap(long& a, long& b);
void swap(int& a, int& b);


// defined here are all the conversion routines among the types 
// int, long, float, double.  See conversions.txt for complete details.



// The following platform-dependent macros are defined:

#define NTL_BITS_PER_LONG      (...)  /* bits in a long */
#define NTL_MAX_LONG           (...)  /* max value of a long */
#define NTL_MIN_LONG           (...)  /* min value of a long */

#define NTL_BITS_PER_INT       (...)  /* bits in a int */
#define NTL_MAX_INT            (...)  /* max value of a int */
#define NTL_MIN_INT            (...)  /* min value of a int */

#define NTL_DOUBLE_PRECISION   (...)  /* # of bits of precision in a double */
#define NTL_FDOUBLE_PRECISION  (...)  /* the double value 
                                        2^{NTL_DOUBLE_PRECISION-1} */

#define NTL_ARITH_RIGHT_SHIFT  (...)  /* 1 if signed right-shift is
                                        arithmetic; 0 otherwise */

#define NTL_EXT_DOUBLE         (...)  /* 1 if platform has "extended" doubles;
                                        0 otherwise */


// ERROR HANDLING

void TerminalError(const char *s);
// print an error message and call abort

extern thread_local void (*ErrorMsgCallback)(const char *);
extern thread_local void (*ErrorCallback)();
// Pointers (initially NULL) to callback functions.
// Upon encountering an unrecoverable error with an error
// message s, the following happens:
//
//    if (ErrorMsgCallback)
//       (*ErrorMsgCallback)(s);
//    else
//       cerr << s << "\n";
// 
//    if (ErrorCallback) (*ErrorCallback)();
//    abort();
//
// NOTE: if threads are enabled, these are actually thread_local variables.



// The following classes are defined even if exceptions are not
// enabled with NTL_EXCEPTIONS

class ErrorObject : public runtime_error {
public:
   ErrorObject(const char *msg);
};

class LogicErrorObject : public ErrorObject {
public:
   LogicErrorObject(const char *msg);
};

class ArithmeticErrorObject : public ErrorObject {
public:
   ArithmeticErrorObject(const char *msg);
};

class ResourceErrorObject : public ErrorObject {
public:
   ResourceErrorObject(const char *msg);
};

class FileErrorObject : public ErrorObject {
public:
   FileErrorObject(const char *msg);
};

class InputErrorObject : public ErrorObject {
public:
   InputErrorObject(const char *msg);
};


// The following functions throw the indicated exception if
// exceptions are enabled with NTL_EXCEPTIONS; otherwise,
// they simply invoke TerminalError.

void MemoryError();
// throws bad_alloc

void Error(const char *msg);
// throws ErrorObject

void LogicError(const char *msg);
// throws LogicErrorObject

void ArithmeticError(const char *msg);
// throws ArithmeticErrorObject

void ResourceError(const char *msg);
// throws ResourceErrorObject

void FileError(const char *msg);
// throws FileErrorObject

void InputError(const char *msg);
// throws InputErrorObject



ntl-11.5.1/doc/vec_GF2.cpp.html0000644417616742025610000004344614064716023017620 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_GF2.cpp.html

/**************************************************************************\

MODULE: vec_GF2

SUMMARY:


The class Vec<GF2> is explicitly specialized.  It behaves much like a generic
Vec<T> (see vector.txt), but there are some differences.

For efficiency, elements of a Vec<GF2> are "packed" into a word.  You can still
use subscript notation v[i] or v(i).  For const vectors, these evaluate to
values of type const GF2.  For non-const vectors, these evaluate to values of
the special type ref_GF2, which is defined in the GF2 header file.

There are implicit conversions from ref_GF2 to const GF2 and from GF2& to
ref_GF2.  Therefore, if you want to declare a function that takes a non-const
reference to a GF2, you should declare the parameter of type ref_GF2: this will
allow you to pass variables of type GF2 as well as elements of vec_GF2's
obtained through indexing.

As an alternative, one can use the get and put methods below to access
vector elements.

There is a subtle but important difference in the semantics of Vec<GF2> and
that of generic NTL vectors.  With a Vec<GF2>, whenever its length is increased
(via SetLength), the "new" bits are always 0.  For example, if 
v.length() == 20, then 

   v.SetLength(10); v.setLength(20);

will effectively clear bits 10..19 of v.  This is quite different from the
semantics of generic NTL vectors, where the above sequence would not change the
value of v at all.  One has to be aware of this difference, but it will not
matter in most ordinary circumstances.


Another thing to be aware of is the use of Vec<GF2> in range-based
for loops.  The safest ways to do this are as follows:

   for (auto&& item : vec) { ... } // for read-only or read/write access

or

   for (GF2 item : vec) { ... } // for access via a copy

Note that:
   * declaring item as "auto&" or "GF2&" will yield a syntax error
   * declaring item as "auto" or "const auto&" will potentially
     allow code to modify vec via item, without a warning or error,
     contrary to expectations (although this cannot happen if vec
     itself is const)

However, declaring item as "auto&&" will work as expected, and the compiler
will raise an error if you try to modify a const Vec<GF2>.  

All of these issues arise because ref_GF2 is not a true reference, and the
semantics of "auto" and "auto&" interact badly.  Similar issues arise with
vector<bool> in the STL.

\**************************************************************************/



template<>
class Vec<GF2> {

public:

   Vec(); // 0 length vector
   Vec(INIT_SIZE_TYPE, long n); // initialize to length n
                                // usage: Vec(INIT_SIZE, n)

   Vec(const Vec<GF2>& a); // copy constructor
   Vec& operator=(const Vec<GF2>& a); // assignment

   Vec(Vec&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy constructor if a is fixed

#ifndef NTL_DISABLE_MOVE_ASSIGN
   Vec& operator=(Vec&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy assignment if *this or a is fixed
#endif

   ~Vec(); // destructor



   void SetLength(long n); // set length to n bits
   void SetLength(long n, GF2 a);
      // set length to n, if length increases, initialize new bits to a

   void SetMaxLength(long n); // allocate space for n bits

   long length() const; // current length, in bits

   long MaxLength() const; // maximum length, i.e., the maximum
                           // value passed to either SetLength or SetMaxLength
                           // since creation or last kill

   long allocated() const; // number of bits for which space is allocated;
                           // if n <= v.allocated(), then v.SetLength(n)
                           // will not result in any memory re-allocation.

   // INVARIANT: 
   //    length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4)


   void FixLength(long n); // fix length to n bits
   // can only be applied after default initialization or kill


   void FixAtCurrentLength();
   // fixes the length at the cuurent length and prohibits
   // all future length changes.  

   // It is required that length() == MaxLength() when called.

   // EXCEPTIONS: if length() != MaxLength() and error is raised;
   // Strong ES.


   long fixed() const; // test if length has been fixed

   void kill(); // free space and make length 0

   const GF2 get(long i) const; // fetch value at index i (indexing from 0)

   void put(long i, GF2 a); // write value a to index i (indexing from 0)
   void put(long i, long a);

// Here are the subscripting operators, defined using the
// "helper" class ref_GF2

   ref_GF2 operator[](long i);
   ref_GF2 operator()(long i);

   const GF2 operator[](long i) const;
   const GF2 operator()(long i) const;


   void swap(Vec<GF2>& y);
   // swap with y (fast: just swaps pointers)

   void move(Vec<GF2>& y);
   // move y to *this (fast: just moves pointers)

   void append(GF2 a);
   // append a to end of vector

   void append(const Vec<GF2>& w);
   // append w to end of vector


// Some partial STL compatibility...also used
// to interface with the Matrix template class

   typedef GF2 value_type;
   typedef ref_GF2 reference;
   typedef const GF2 const_reference;
   typedef /* implementation defined type */ iterator;
   typedef /* implementation defined type */ const_iterator;

   ref_GF2 at(long i);
   const GF2 at(long i) const;
   // indexing with range checking


   iterator begin();
   const_iterator begin() const;
   // pointer to beginning of vector

   iterator end();
   const_iterator end() const;
   // pointer to (one past) end of vector

   // NOTES: The iterator types act like pointers.  You can perform all the
   // usual arithmetic on them, as well as dereferencing and subscripting.
   // Dereferencing an iterator yields a ref_GF2.  Dereferencing a
   // const_iterator yields a const GF2.


};



void swap(Vec<GF2>& x, Vec<GF2>& y);
// swap x and y (fast pointer swap)

void append(Vec<GF2>& v, GF2 a);
// append a to v

void append(Vec<GF2>& v, const Vec<GF2>& a);
// append a to v

// equality operators:

long operator==(const Vec<GF2>& a, const Vec<GF2>& b);
long operator!=(const Vec<GF2>& a, const Vec<GF2>& b);


// I/O operators:

ostream& operator<<(ostream& s, const Vec<GF2>& a);
istream& operator>>(istream& s, Vec<GF2>& a);

// The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1".
// On input, the a_i may be arbitrary integers, which are reduced mod 2.



typedef Vec<GF2> vec_GF2;  // backward compatibility

// utility routines:

void clear(vec_GF2& x); // clear all bits--length unchanged
long IsZero(const vec_GF2& a); // test if all bits are zero

void shift(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 shift(const vec_GF2& a, long n);
// x = a shifted n places, where n may be positive or negative.
// Generally, x[i] = a[i-n], so positive n shifts to a higher index.
// The length of x is set to the length of a, and bits 
// are zero-filled or discarded as necessary.

void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed
vec_GF2 reverse(const vec_GF2& a);

long weight(const vec_GF2& a); // return number of 1 bits in a


// arithmetic operations over GF(2):

void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void negate(vec_GF2& x, const vec_GF2& a);

void mul(vec_GF2& x, const vec_GF2& a, GF2 b);
void mul(vec_GF2& x, const vec_GF2& a, long b);

void mul(vec_GF2& x, GF2 a, const vec_GF2& b);
void mul(vec_GF2& x, long a, const vec_GF2& b);
// x = a * b

void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b);
// vectors may differ in length

void VectorCopy(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 VectorCopy(const vec_GF2& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_GF2& x, long n);  // x = random vector of length n
vec_GF2 random_vec_GF2(long n);



// arithmetic operator notation:

vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a);

// scalar mul:

vec_GF2 operator*(const vec_GF2& a, GF2 b);
vec_GF2 operator*(const vec_GF2& a, long b);

vec_GF2 operator*(GF2 a, const vec_GF2& b);
vec_GF2 operator*(long a, const vec_GF2& b);

// inner product: 

inline GF2 operator*(const vec_GF2& a, const vec_GF2& b);

// assignment operator notation:

vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a);
vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a);

vec_GF2& operator*=(vec_GF2& x, GF2 a);
vec_GF2& operator*=(vec_GF2& x, long a);

ntl-11.5.1/doc/vec_GF2E.cpp.html0000644417616742025610000001646014064716023017721 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_GF2E.cpp.html

/**************************************************************************\

MODULE: vec_GF2E

SUMMARY:

Provides vectors over GF2E, along with some related operations.

\**************************************************************************/

#include <NTL/GF2E.h>
#include <NTL/vector.h>


typedef Vec<GF2E> vec_GF2E; // backward compatibility

void mul(vec_GF2E& x, const vec_GF2E& a, const GF2E& b);
void mul(vec_GF2E& x, const vec_GF2E& a, GF2 b);
void mul(vec_GF2E& x, const vec_GF2E& a, long b);

void mul(vec_GF2E& x, const GF2E& a, const vec_GF2E& b);
void mul(vec_GF2E& x, GF2 a, const vec_GF2E& b);
void mul(vec_GF2E& x, long a, const vec_GF2E& b);
// x = a * b

void add(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = a + b

void sub(vec_GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = a - b = x + a

void negate(vec_GF2E& x, const vec_GF2E& a);
// x = - a = a

void clear(vec_GF2E& x);
// x = 0 (length unchanged)

long IsZero(const vec_GF2E& a);
// test if a is the zero vector



void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(), b.length())

void InnerProduct(GF2E& x, const vec_GF2E& a, const vec_GF2E& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_GF2E& x, const vec_GF2E& a, long n);
vec_GF2E VectorCopy(const vec_GF2E& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_GF2E& x, long n);  // x = random vector of length n
vec_GF2E random_vec_GF2E(long n);


// operator notation:

vec_GF2E
operator+(const vec_GF2E& a, const vec_GF2E& b);

vec_GF2E
operator-(const vec_GF2E& a, const vec_GF2E& b);

vec_GF2E operator-(const vec_GF2E& a);


// vector/scalar multiplication:

vec_GF2E operator*(const vec_GF2E& a, const GF2E& b);
vec_GF2E operator*(const vec_GF2E& a, GF2 b);
vec_GF2E operator*(const vec_GF2E& a, long b);

vec_GF2E operator*(const GF2E& a, const vec_GF2E& b);
vec_GF2E operator*(GF2 a, const vec_GF2E& b);
vec_GF2E operator*(long a, const vec_GF2E& b);

// inner product:

GF2E operator*(const vec_GF2E& a, const vec_GF2E& b);


// assignment operator notation:

vec_GF2E& operator+=(vec_GF2E& x, const vec_GF2E& a);
vec_GF2E& operator-=(vec_GF2E& x, const vec_GF2E& a);

vec_GF2E& operator*=(vec_GF2E& x, const GF2E& a);
vec_GF2E& operator*=(vec_GF2E& x, GF2 a);
vec_GF2E& operator*=(vec_GF2E& x, long a);



// Implementation note: the BlockConstruct routine has been customized
// for GF2E so that when a vec_GF2E is grown, space for the needed
// elements is allocated in one contiguous chunk.  This saves on calls to
// malloc and free, and should also yield better locality of reference.
// One consequence of this is that swapping an element of a vec_GF2E
// with another GF2E can not be implemented by pointer swap, and will in
// this case be done by copy.
ntl-11.5.1/doc/vec_RR.cpp.html0000644417616742025610000001235614064716023017561 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_RR.cpp.html

/**************************************************************************\

MODULE: vec_RR

SUMMARY:

Defines the class vec_RR.

\**************************************************************************/


typedef Vec<RR> vec_RR; // backward compatibility

void mul(vec_RR& x, const vec_RR& a, const RR& b);
void mul(vec_RR& x, const vec_RR& a, double b);

void mul(vec_RR& x, const RR& a, const vec_RR& b);
void mul(vec_RR& x, double a, const vec_RR& b);
// x = a * b


void add(vec_RR& x, const vec_RR& a, const vec_RR& b);
// x = a + b

void sub(vec_RR& x, const vec_RR& a, const vec_RR& b);
// x = a - b

void clear(vec_RR& x);
// x = 0 (length unchanged)

void negate(vec_RR& x, const vec_RR& a);
// x = -a

long IsZero(const vec_RR& a);
// test if a is the zero vector


void InnerProduct(RR& x, const vec_RR& a, const vec_RR& b);
// x = inner product of a and b, padded with zeros to make the lengths
// even.

void VectorCopy(vec_RR& x, const vec_RR& a, long n);
vec_RR VectorCopy(const vec_RR& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.


// operator notation:

vec_RR operator+(const vec_RR& a, const vec_RR& b);
vec_RR operator-(const vec_RR& a, const vec_RR& b);

vec_RR operator-(const vec_RR& a);


// vector/scalar multiplication:

vec_RR operator*(const vec_RR& a, const RR& b);
vec_RR operator*(const vec_RR& a, double b);

vec_RR operator*(const RR& a, const vec_RR& b);
vec_RR operator*(double a, const vec_RR& b);

// inner product:

RR operator*(const vec_RR& a, const vec_RR& b);


// assignment operator notation:

vec_RR& operator+=(vec_RR& x, const vec_RR& a);
vec_RR& operator-=(vec_RR& x, const vec_RR& a);

vec_RR& operator*=(vec_RR& x, const RR& a);
vec_RR& operator*=(vec_RR& x, double a);


ntl-11.5.1/doc/vec_ZZ.cpp.html0000644417616742025610000001234314064716023017575 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_ZZ.cpp.html

/**************************************************************************\

MODULE: vec_ZZ

SUMMARY:

Defines the class vec_ZZ.

\**************************************************************************/


typedef Vec<ZZ> vec_ZZ; // backward compatibility

void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b);
void mul(vec_ZZ& x, const vec_ZZ& a, long b);

void mul(vec_ZZ& x, const ZZ& a, const vec_ZZ& b);
void mul(vec_ZZ& x, long a, const vec_ZZ& b);
// x = a * b

void add(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = a + b

void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = a - b

void clear(vec_ZZ& x);
// x = 0 (length unchanged)

void negate(vec_ZZ& x, const vec_ZZ& a);
// x = -a

long IsZero(const vec_ZZ& a);
// test if a is the zero vector

void InnerProduct(ZZ& x, const vec_ZZ& a, const vec_ZZ& b);
// x = inner product of a and b, padded with zeros to make the lengths
// even.

void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n);
vec_ZZ VectorCopy(const vec_ZZ& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.


// operator notation:

vec_ZZ operator+(const vec_ZZ& a, const vec_ZZ& b);
vec_ZZ operator-(const vec_ZZ& a, const vec_ZZ& b);

vec_ZZ operator-(const vec_ZZ& a);


// vector/scalar multiplication:

vec_ZZ operator*(const vec_ZZ& a, const ZZ& b);
vec_ZZ operator*(const vec_ZZ& a, long b);

vec_ZZ operator*(const ZZ& a, const vec_ZZ& b);
vec_ZZ operator*(long a, const vec_ZZ& b);

// inner product:

ZZ operator*(const vec_ZZ& a, const vec_ZZ& b);



// assignment operator notation:

vec_ZZ& operator+=(vec_ZZ& x, const vec_ZZ& a);
vec_ZZ& operator-=(vec_ZZ& x, const vec_ZZ& a);

vec_ZZ& operator*=(vec_ZZ& x, const ZZ& a);
vec_ZZ& operator*=(vec_ZZ& x, long a);


ntl-11.5.1/doc/vec_ZZ_p.cpp.html0000644417616742025610000001563214064716023020120 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_ZZ_p.cpp.html

/**************************************************************************\

MODULE: vec_ZZ_p

SUMMARY:

Provides vectors over ZZ_p, along with some related operations.

\**************************************************************************/

#include <NTL/ZZ_p.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>


typedef Vec<ZZ_p> vec_ZZ_p; // backward compatibility

void mul(vec_ZZ_p& x, const vec_ZZ_p& a, const ZZ_p& b);
void mul(vec_ZZ_p& x, const vec_ZZ_p& a, long b);

void mul(vec_ZZ_p& x, const ZZ_p& a, const vec_ZZ_p& b);
void mul(vec_ZZ_p& x, long a, const vec_ZZ_p& b);
// x = a * b

void add(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = a + b

void sub(vec_ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = a - b

void clear(vec_ZZ_p& x);
// x = 0 (length unchanged)

void negate(vec_ZZ_p& x, const vec_ZZ_p& a);
// x = -a

long IsZero(const vec_ZZ_p& a);
// test if a is the zero vector


void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(ZZ_p& x, const vec_ZZ_p& a, const vec_ZZ_p& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_ZZ_p& x, const vec_ZZ_p& a, long n);
vec_ZZ_p VectorCopy(const vec_ZZ_p& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_ZZ_p& x, long n);  // x = random vector of length n
vec_ZZ_p random_vec_ZZ_p(long n);




// operator notation:

vec_ZZ_p operator+(const vec_ZZ_p& a, const vec_ZZ_p& b);
vec_ZZ_p operator-(const vec_ZZ_p& a, const vec_ZZ_p& b);

vec_ZZ_p operator-(const vec_ZZ_p& a);


// vector/scalar multiplication:

vec_ZZ_p operator*(const vec_ZZ_p& a, const ZZ_p& b);
vec_ZZ_p operator*(const vec_ZZ_p& a, long b);

vec_ZZ_p operator*(const ZZ_p& a, const vec_ZZ_p& b);
vec_ZZ_p operator*(long a, const vec_ZZ_p& b);

// inner product:

ZZ_p operator*(const vec_ZZ_p& a, const vec_ZZ_p& b);


// assignment operator notation:

vec_ZZ_p& operator+=(vec_ZZ_p& x, const vec_ZZ_p& a);
vec_ZZ_p& operator-=(vec_ZZ_p& x, const vec_ZZ_p& a);

vec_ZZ_p& operator*=(vec_ZZ_p& x, const ZZ_p& a);
vec_ZZ_p& operator*=(vec_ZZ_p& x, long a);



// Implementation note: the BlockConstruct routine has been customized
// for ZZ_p so that when a vec_ZZ_p is grown, space for the needed
// elements is allocated in one contiguous chunk.  This saves on calls to
// malloc and free, and should also yield better locality of reference.
// One connsequence of this is that swapping an element of a vec_ZZ_p
// with another ZZ_p can not be implemented by pointer swap, and will in
// this case be done by copy.
ntl-11.5.1/doc/vec_ZZ_pE.cpp.html0000644417616742025610000001602214064716023020217 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_ZZ_pE.cpp.html

/**************************************************************************\

MODULE: vec_ZZ_pE

SUMMARY:

Provides vectors over ZZ_pE, along with some related operations.

\**************************************************************************/

#include <NTL/ZZ_pE.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>

typedef Vec<ZZ_pE> vec_ZZ_pE; // backward compatibility

void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_pE& b);
void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, const ZZ_p& b);
void mul(vec_ZZ_pE& x, const vec_ZZ_pE& a, long b);

void mul(vec_ZZ_pE& x, const ZZ_pE& a, const vec_ZZ_pE& b);
void mul(vec_ZZ_pE& x, const ZZ_p& a, const vec_ZZ_pE& b);
void mul(vec_ZZ_pE& x, long a, const vec_ZZ_pE& b);
// x = a * b

void add(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = a + b

void sub(vec_ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = a - b

void clear(vec_ZZ_pE& x);
// x = 0 (length unchanged)

void negate(vec_ZZ_pE& x, const vec_ZZ_pE& a);
// x = -a

long IsZero(const vec_ZZ_pE& a);
// test if a is the zero vector


void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(ZZ_pE& x, const vec_ZZ_pE& a, const vec_ZZ_pE& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_ZZ_pE& x, const vec_ZZ_pE& a, long n);
vec_ZZ_pE VectorCopy(const vec_ZZ_pE& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_ZZ_pE& x, long n);  // x = random vector of length n
vec_ZZ_pE random_vec_ZZ_pE(long n);



// operator notation:

vec_ZZ_pE operator+(const vec_ZZ_pE& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator-(const vec_ZZ_pE& a, const vec_ZZ_pE& b);

vec_ZZ_pE operator-(const vec_ZZ_pE& a);


// vector/scalar multiplication:

vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_pE& b);
vec_ZZ_pE operator*(const vec_ZZ_pE& a, const ZZ_p& b);
vec_ZZ_pE operator*(const vec_ZZ_pE& a, long b);

vec_ZZ_pE operator*(const ZZ_pE& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator*(const ZZ_p& a, const vec_ZZ_pE& b);
vec_ZZ_pE operator*(long a, const vec_ZZ_pE& b);

// inner product:

ZZ_pE operator*(const vec_ZZ_pE& a, const vec_ZZ_pE& b);


// assignment operator notation:

vec_ZZ_pE& operator+=(vec_ZZ_pE& x, const vec_ZZ_pE& a);
vec_ZZ_pE& operator-=(vec_ZZ_pE& x, const vec_ZZ_pE& a);

vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_pE& a);
vec_ZZ_pE& operator*=(vec_ZZ_pE& x, const ZZ_p& a);
vec_ZZ_pE& operator*=(vec_ZZ_pE& x, long a);

ntl-11.5.1/doc/vec_lzz_p.cpp.html0000644417616742025610000001511114064716023020364 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_lzz_p.cpp.html

/**************************************************************************\

MODULE: vec_zz_p

SUMMARY:

Provides vectors over zz_p, along with some related operations.

\**************************************************************************/

#include "zz_p.h"
#include "vec_zz.h"
#include <NTL/vector.h>

typedef Vec<zz_p> vec_zz_p; // backward compatibility

void mul(vec_zz_p& x, const vec_zz_p& a, zz_p b);
void mul(vec_zz_p& x, const vec_zz_p& a, long b);

void mul(vec_zz_p& x, zz_p a, const vec_zz_p& b);
void mul(vec_zz_p& x, long a, const vec_zz_p& b);
// x = a * b

void add(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = a + b

void sub(vec_zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = a - b

void clear(vec_zz_p& x);
// x = 0 (length unchanged)

void negate(vec_zz_p& x, const vec_zz_p& a);
// x = -a

long IsZero(const vec_zz_p& a);
// test if a is the zero vector

void VectorCopy(vec_zz_p& x, const vec_zz_p& a, long n);
vec_zz_p VectorCopy(const vec_zz_p& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_zz_p& x, long n);  // x = random vector of length n
vec_zz_p random_vec_zz_p(long n);


void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

long CRT(vec_ZZ& a, ZZ& prod, const vec_zz_p& A);
// Incremental Chinese Remaindering: If p is the current zz_p modulus with
// (p, prod) = 1; Computes a' such that a' = a mod prod and a' = A mod p,
// with coefficients in the interval (-p*prod/2, p*prod/2]; 
// Sets a := a', prod := p*prod, and returns 1 if a's value changed.


// operator notation:

vec_zz_p operator+(const vec_zz_p& a, const vec_zz_p& b);
vec_zz_p operator-(const vec_zz_p& a, const vec_zz_p& b);

vec_zz_p operator-(const vec_zz_p& a);


// vector/scalar multiplication:

vec_zz_p operator*(const vec_zz_p& a, zz_p b);
vec_zz_p operator*(const vec_zz_p& a, long b);

vec_zz_p operator*(zz_p a, const vec_zz_p& b);
vec_zz_p operator*(long a, const vec_zz_p& b);


// inner product:

zz_p operator*(const vec_zz_p& a, const vec_zz_p& b);



// assignment operator notation:

vec_zz_p& operator+=(vec_zz_p& x, const vec_zz_p& a);
vec_zz_p& operator-=(vec_zz_p& x, const vec_zz_p& a);

vec_zz_p& operator*=(vec_zz_p& x, zz_p a);
vec_zz_p& operator*=(vec_zz_p& x, long a);

ntl-11.5.1/doc/vec_lzz_pE.cpp.html0000644417616742025610000001602514064716023020476 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vec_lzz_pE.cpp.html

/**************************************************************************\

MODULE: vec_zz_pE

SUMMARY:

Provides vectors over zz_pE, along with some related operations.

\**************************************************************************/

#include <NTL/lzz_pE.h>
#include <NTL/vec_ZZ.h>
#include <NTL/vector.h>

typedef Vec<zz_pE> vec_zz_pE; // backward compatibility

void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_pE& b);
void mul(vec_zz_pE& x, const vec_zz_pE& a, const zz_p& b);
void mul(vec_zz_pE& x, const vec_zz_pE& a, long b);

void mul(vec_zz_pE& x, const zz_pE& a, const vec_zz_pE& b);
void mul(vec_zz_pE& x, const zz_p& a, const vec_zz_pE& b);
void mul(vec_zz_pE& x, long a, const vec_zz_pE& b);
// x = a * b

void add(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = a + b

void sub(vec_zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = a - b

void clear(vec_zz_pE& x);
// x = 0 (length unchanged)

void negate(vec_zz_pE& x, const vec_zz_pE& a);
// x = -a

long IsZero(const vec_zz_pE& a);
// test if a is the zero vector


void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b);
// x = sum_{i=0}^{n-1} a[i]*b[i], where n = min(a.length(),
// b.length())

void InnerProduct(zz_pE& x, const vec_zz_pE& a, const vec_zz_pE& b,
                  long offset);
// x = sum_{i=offset}^{n-1} a[i]*b[i-offset], where n = min(a.length(),
// b.length()+offset)

void VectorCopy(vec_zz_pE& x, const vec_zz_pE& a, long n);
vec_zz_pE VectorCopy(const vec_zz_pE& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_zz_pE& x, long n);  // x = random vector of length n
vec_zz_pE random_vec_zz_pE(long n);




// operator notation:

vec_zz_pE operator+(const vec_zz_pE& a, const vec_zz_pE& b);
vec_zz_pE operator-(const vec_zz_pE& a, const vec_zz_pE& b);

vec_zz_pE operator-(const vec_zz_pE& a);


// vector/scalar multiplication:

vec_zz_pE operator*(const vec_zz_pE& a, const zz_pE& b);
vec_zz_pE operator*(const vec_zz_pE& a, const zz_p& b);
vec_zz_pE operator*(const vec_zz_pE& a, long b);

vec_zz_pE operator*(const zz_pE& a, const vec_zz_pE& b);
vec_zz_pE operator*(const zz_p& a, const vec_zz_pE& b);
vec_zz_pE operator*(long a, const vec_zz_pE& b);

// inner product:

zz_pE operator*(const vec_zz_pE& a, const vec_zz_pE& b);


// assignment operator notation:

vec_zz_pE& operator+=(vec_zz_pE& x, const vec_zz_pE& a);
vec_zz_pE& operator-=(vec_zz_pE& x, const vec_zz_pE& a);

vec_zz_pE& operator*=(vec_zz_pE& x, const zz_pE& a);
vec_zz_pE& operator*=(vec_zz_pE& x, const zz_p& a);
vec_zz_pE& operator*=(vec_zz_pE& x, long a);

ntl-11.5.1/doc/vector.cpp.html0000644417616742025610000011201714064716023017676 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/vector.cpp.html


/**************************************************************************\

MODULE: vector

SUMMARY:

Template class for dynamic-sized vectors.

The declaration

   Vec<T> v;

creates a zero-length vector.  To grow this vector to length n,
execute

   v.SetLength(n)

This causes space to be allocated for (at least) n elements, and also causes
the default constructor for T to be called to initialize these elements.

The current length of a vector is available as v.length().

Let n = v.length().  Calling v.SetLength(m) with m <= n sets the current length
of v to m (but does not call any destructors or free any space).  Calling
v.SetLength(m) with m > n will allocate space and initialize as necessary, but
will leave the values of the already allocated elements unchanged (although
their addresses may change).  If T has a user-defined default constructor, that
is invoked.  Otherwise, the new memory locations are "default initialized".  In
particular, this means that POD types may be uninitialized.

v.MaxLength() is the largest value of n for which v.SetLength(n) was invoked,
and is equal to the number of entries that have been initialized.
v.SetMaxLength(n) will allocate space for and initialize up to n elements,
without changing v.length().

When v's destructor is called, all constructed elements will be destructed, and
all space will be relinquished.

v.allocated() is the number of elements which have been allocated,
which may be more than the number elements initialized.
Note that if n <= v.allocated(), then v.SetLength(n) is guaranteed
not to cause any memory allocation or movement of objects.

Space is managed using malloc, realloc, and free.  When a vector is grown, a
bit more space may be allocated than was requested for efficiency reasons.

Note that when a vector is grown, the objects in the vector may have moved,
possibly creating dangling references to vector elements.  One has to be
especially careful of this when using vectors passed as reference parameters
that may alias one another.


----------------------
IMPLEMENTATION DETAILS
----------------------

A Vec<T> object is just a pointer to the first element of the array.  There is
a control block immediately before the first element that keeps track of
several parameters: 
   len    -- the logical length of the array (returned by length())
   init   -- the number of elements constructed (returned ny MaxLength())
   alloc  -- the number of elements for which space has been allocated
             (returned by allocated())
   fixed  -- flag that indicates that the length is fixed 
             (returned by fixed())

Note that 0 <= len <= init <- alloc



---------------
SPECIALIZATIONS
---------------

NTL currently defines an optimized specialization Vec<GF2>.  There are a few
quirks to be aware of.  See the documentation file for vec_GF2 for more
details.


---------------------
RANGE-BASED FOR LOOPS
---------------------

NTL's vectors provide sufficient functionality to enable range-based for-loops
(in C++11).  The safest ways to use this functionality are to write:

   for (auto&& item : vec) { ... } // for read-only or read/write access

or

   for (T item : vec) { ... } // for access via a copy

This is especially true if vec may be of type Vec<GF2>.  Again, see the
documentation file for vec_GF2 for more details.


--------------
OTHER FEATURES
--------------

The i-th vector element (counting from 0) is accessed as v[i].  If the macro
NTL_RANGE_CHECK is defined, code is emitted to test if 0 <= i < v.length().
This check is not performed by default.

For old-time FORTRAN programmers, the i-th vector element (counting from 1) is
accessed as v(i).

--------------------
REALLOCATION DETAILS
--------------------

When a vector is resized and not enough space has been allocated, then a
reallocation process takes place.  There are several strategies which can be
used, which we list here from least to most efficient.


COPY AND DESTROY STRATEGY:
This is the same strategy used by the STL prior to C++11.  New memory is
allocated, and each element of the vector is copied (using a copy constructor)
to the new memory, and then all the elements in the old memory is destroyed
(using a destructor).  While much safer than the Realloc Strategy, it can be a
bit slower.

MOVE STRATEGY:
This is a strategy that is also used by the STL, assuming C++11.  New memory is
allocated, and each element of the vector is moved (using a move constructor)
to the new memory, and then all the elements in the old memory is destroyed
(using a destructor).  This strategy is only viable if the underlying type has
a "nothrow" move constructor.  Typically, it will be significantly faster than
the Copy and Destroy Strategy.

REALLOC STRATEGY:
This strategy simply calls the realloc function, which may result in objects
being copied bit-wise from one location in memory to another.  For most types
of objects, even those with non-trivial constructors and destructors, this is
perfectly safe, as most objects really don't care what address they are stored
at.  As an example of where this doesn't work, STL string implementations using
a "short string" optimization may consist of an object containing a pointer to
a sub-object, which would be invalidated if the object were bit-wise moved from
one location to another.  This strategy is the fastest of them all.

CHOOSING A STRATEGY:
In the implementation of Vec<T>, NTL will opt for the Realloc Strategy
if one of the two conditions hold:
   (i) T has a trivial copy constructor and a trivial destructor, or
   (iii) T is a class that has been explicit declared "relocatable".
(See below for details on how to declare that a class is relocatable.)
Otherwise, NTL will use the Move Strategy if T has a nothrow move costructor.
Otherwise, NTL will use the Copy Strategy if T has a copy constructor that is
accessible (i.e., not private and not deleted).  Otherwise, no reallocation
implementation is provided, and a runtime error will be raised if a
reallocation is required (this provides maximum flexiblilty and also maximum
backward compatibility with previous versions of NTL, even though sometimes a
compile-time diagnostic would be preferable).


DECLARING A CLASS RELOCATABLE:
One can declare T to be relocatable by adding the following line of code
immediately after the definition of class T:

   NTL_DECLARE_RELOCATABLE((T*))

Notice the double parentheses and the "*" --- these are unfortunately 
necessary.  This macro expands as 

   constexpr bool DeclareRelocatableType(T*) { return true; }

Inside the class Vec<T>, this function is invoked with ((T*) 0) as the
argument.  By declaring relocatability via a function definition in this way,
the Vec<T> class will always find (via "Koenig lookup", or ADL) the declaration
for T in the namespace in which T is defined (assuming you put the
relocatability declaration there as well).

You can also declare a template class to be relocatable, as in:

   template<class X, class Y>
   NTL_DECLARE_RELOCATABLE((T<X,Y>*))

There is also a macro NTL_DECLARE_RELOCATABLE_WHEN, which leaves off the
function body, if you want something other than { return true; }

NTL also defines template functions:

   template<class T>
   constexpr bool DeclareRelocatableType(T*) 
   { return ... ;  }

where "..." is an expression that returns true if T is a simple type that is
safe to relocate, as determined by C++11 type traits.  Such simple types
include scalar types and simple classes with trivial copy constructor and
destructor.

NTL already declares as relocatable most if the fundamental types fot which it
makes sense to do so.

UNSAFE VECTOR MODE:
The above describes the default behavior of NTL as of version 11.0.  Prior to
version 11.0, the default behavior was to only use the Realloc Strategy, which
is potentially unsafe.  You can revert to this old behavior by configuring
NTL_SAFE_VECTORS=off.


-------------------------
COMPARISON TO STL VECTORS 
-------------------------

When the length of an NTL vector is reduced, no objects are destroyed.
In contrast, when the length of an STL vector is reduced, objects are
destroyed (effectively, maintaining the invariant len == init).

Also, STL vectors never use anything like the Realloc Strategy.


----------------------
HISTORICAL PERSPECTIVE
----------------------

When I first started working on NTL around 1990, C++ was a much simpler
language.  Among other things, there were no templates and no STL, so the Vec
class started out (and remained, for many years) a set of macros (indeed, this
approach was advocated in the first edition of Stroustrup's book).

My thinking at that time was very much "C oriented".  The idea of resizing a
vector without using realloc never occured to me, and all of the classes I
wanted to put in vectors were relocatable.  Why would you ever bother making
copies of vector elements and destroy the originals when you could just
realloc?  It wasn't until many years later that I even realized this was
somehow questionable practice.  Indeed, resizing via malloc is technically
undefined behavior, but it's been working for me for over 25 years without
problems.

Furthermore, because of the poor performance of malloc in those days (which is
much better now), I designed the Vec<ZZ_p> class (and a few others) to allocate
the underlying ZZ's in blocks.  This not only reduces the number of calls to
malloc, but it also gives better locality of reference.  Experiments in the
last couple of years show that this is still benefit to doing this.

With all of these design decisions baked into NTL's Vec class, transitioning to
STL vectors would be problematic, and is unlikely to ever happen.  But as
things have evolved, NTL Vec's offers many of the same convenience and safety
features as STL vector's.


\**************************************************************************/


// EXCEPTIONS: all functions below do not throw any exceptions,
//   except as noted

template<class T>
class Vec {
public:

   Vec();  // initially length 0

   Vec(const Vec& a);
   // copy constructor;  uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   // EXCEPTIONS: may throw

   Vec& operator=(const Vec& a);
   // assignment;  uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   // EXCEPTIONS: weak ES (but if it throws, neither length nor MaxLength
   //    will change, although some previously initialized elements
   //    may have been assigned new values).


   Vec(Vec&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy constructor if a is fixed

   Vec& operator=(Vec&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy assignment if *this or a is fixed

   // NOTE: If neither source nor destination are fixed, these operations will
   // be fast pointer moves and no exceptions will be thrown.  If either are
   // fixed (say, the row in a Mat<T>), these operations revert to copy
   // operations, which may either throw an exception (if NTL_EXCEPTIONS is on)
   // or abort the program (if NTL_EXCEPTIONS is off).

   // NOTE: In a vector copy assignment x=a, all iterators, references,
   // and pointers related to x may be invalidated by the assignment.
   // In a vector move assignment, the same applies to a as well.

   // BACKWARD COMPATIBILITY: after introducing of "move constructors" in NTL
   // 10.4, there have been some reports of incompatibilties.  Some legacy NTL
   // clients have been known to assume that x=a does not invalidate pointers
   // into x, provided x.length() >= a.length() before the assignment.  This
   // assumption is not valid, however, for a move assignment.  Because of this
   // problem, as of NTL 11.0, move assignments have been disabled by default
   // (this is controlled by the configuration flag NTL_DISABLE_MOVE_ASSIGN).
   // This affects vectors and matrices,  as well as many other types (such as
   // polynomials) that are implemented in terms of vectors.  Move assignment
   // is not disabled.


   ~Vec();
   // destructor: calls T's destructor for all initialized
   // elements in the vector, and then frees the vector itself

   void SetLength(long n);
   // set current length to n, growing vector if necessary
   // new objects are initialized using the default contructor for T

   // EXCEPTIONS: strong ES (but the vector may have been
   //    reallocated)

   void SetLength(long n, const T& a);
   // set current length to n, growing vector if necessary
   // new objects are initialized using the copy contructor for T

   // EXCEPTIONS: strong ES (but the vector may have been
   //    reallocated)

   template<class F>
   void SetLengthAndApply(long n, F f);
   // set current length to n, growing vector if necessary
   // any new objects are initialized using defauly constructor
   // for T, and after that, f is applied to each new object x
   // as f(x).

   // EXCEPTIONS: strong ES (but the vector may have been
   //    reallocated)

   long length() const;
   // current length

   T& operator[](long i);
   const T& operator[](long i) const;
   // indexing operation, starting from 0.
   // The first version is applied to non-const Vec<T>,
   // and returns a non-const reference to a T, while the second version
   // is applied to a const Vec<T> and returns a const reference to a T.

   // EXCEPTIONS: may throw if range checking turned on, strong ES

   T& operator()(long i);
   const T& operator()(long i) const;
   // indexing operation, starting from 1
   // The first version is applied to non-const Vec<T>,
   // and returns a non-const reference to a T, while the second version
   // is applied to a const Vec<T> and returns a const reference to a T.

   // EXCEPTIONS: may throw if range checking turned on, strong ES

   T* elts();
   const T* elts() const;
   // returns address of first vector element (or 0 if no space has been
   // allocated for this vector).  If a vector potentially has length 0, it is
   // safer to write v.elts() instead of &v[0]: the latter is not well defined
   // by the C++ standard (although this is likely an academic concern).
   //
   // The first version is applied to non-const Vec<T>, and returns a non-const
   // pointer to a T, while the second version is applied to a const Vec<T> and
   // returns a const reference to a T.


   void swap(Vec& y);
   // swap with y (fast: just swaps pointers)

   // EXCEPTIONS: throws if vectors are fixed and lengths do not match, strong ES

   void move(Vec& y);
   // move y into *this, killing y (fast: just moves pointers)

   // EXCEPTIONS: strong ES, raises an error if 
   // &y != this and either y or *this are fixed

   void append(const T& a);
   // append a to end of vector; uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   // EXCEPTIONS: strong ES if initializing a new element (and in any 
   //    case, if an exception throws, length and MaxLength remain 
   //    unchanged).

   void append(const Vec& w);
   // append w to end of vector; uses the assignment operator of T
   // for copying into locations that have already been initialized,
   // and uses the copy constructor for T for initializing new locations.

   // EXCEPTIONS: strong ES if initializing new elements (and in any 
   //    case, if an exception throws, length and MaxLength remain 
   //    unchanged).


// Alternative access interface 

   const T& get(long i) const;
   // v.get(i) returns v[i]

   void put(long i, const T& a);
   // v.put(i, a) equivalent to v[i] = q



// Some STL compatibility

   typedef T value_type;
   typedef value_type& reference;
   typedef const value_type& const_reference;
   typedef value_type *iterator;
   typedef const value_type *const_iterator;

   T* data();
   const T* data() const;
   // v.data() same as v.elts()

   T* begin();
   const T* begin() const;
   // v.begin() same as v.elts()

   T* end();
   const T* end() const;
   // pointer to (one past) last element (or NULL)

   T& at(long i);
   const T& at(long i) const;
   // indexing with range checking


// the remaining member functions are a bit esoteric (skip on first
// reading)

   Vec(INIT_SIZE_TYPE, long n);
   // Vec(INIT_SIZE, n) initializes vector with an intial length of n.
   // new objects are initialized using the default contructor for T

   // EXCEPTIONS: may throw

   Vec(INIT_SIZE_TYPE, long n, const T& a);
   // Vec(INIT_SIZE, n, a) initializes vector with an intial length of n.
   // new objects are initialized using the copy contructor for T

   // EXCEPTIONS: may throw

   void kill();
   // release space and set to length 0

   void SetMaxLength(long n);
   // allocates space and initializes up to n elements. Does not change
   // current length

   // EXCEPTIONS: may throw, strong ES

   void FixLength(long n);
   // sets length to n and prohibits all future length changes.
   // FixLength may only be invoked immediately after the default
   // construction or kill.

   // The kill operation is also subsequently prohibited, and swap is
   // allowed on fixed length vectors of the same length.

   // FixLength is provided mainly to implement Mat<T>, to enforce
   // the restriction that all rows have the same length.

   // EXCEPTIONS: may throw, strong ES

   void FixAtCurrentLength();
   // fixes the length at the cuurent length and prohibits
   // all future length changes.  

   // It is required that length() == MaxLength() when called.

   // EXCEPTIONS: if length() != MaxLength() and error is raised;
   // if length() == 0, a memory allocation error may be raised.
   // Strong ES.

   long fixed() const;
   // test if length has been fixed by FixLength() or FixAtCurrentLength()

   long MaxLength() const;
   // maximum length, i.e., number of allocated and initialized elements

   long allocated() const;
   // the number of objects for which space has been allocated, but not
   // necessarily initialized;  this may be larger than MaxLength().

   T& RawGet(long i);
   const T& RawGet(long i) const;
   // indexing with no range checking

   long position(const T& a) const;
   // returns position of a in the vector, or -1 if it is not there.
   // The search is conducted from position 0 to allocated()-1 the vector, 
   // and an error is raised if the object is found at position MaxLength()
   // or higher (in which case a references an uninitialized object).
   // Note that if NTL_CLEAN_PTR flag is set, this routine takes
   // linear time, and otherwise, it takes constant time.

   // EXCEPTIONS: may throw (as indicated above)

   long position1(const T& a) const;
   // returns position of a in the vector, or -1 if it is not there.
   // The search is conducted from position 0 to length()-1 of the vector.
   // Note that if NTL_CLEAN_PTR flag is set, this routine takes
   // linear time, and otherwise, it takes constant time.

};


/**************************************************************************\

                       Some utility routines

\**************************************************************************/


template<class T>
void swap(Vec<T>& x, Vec<T>& y);
// swaps x & y; same as x.swap(y)

// EXCEPTIONS: same as for swap member function

template<class T>
void append(Vec<T>& v, const T& a);
// appends a to the end of v; same as v.append(a)

// EXCEPTIONS: same as for append member function

template<class T>
void append(Vec<T>& v, const Vec<T>& w);
// appends w to the end of v; same as v.append(w)

// EXCEPTIONS: same as for append member function



/**************************************************************************\

                             Input/Output


The I/O format for a vector v with n elements is:

   [v[0] v[1] ... v[n-1]]

Uses corresponding I/O operators for T

\**************************************************************************/

template<class T>
istream& operator>>(istream&, Vec<T>&);

// EXCEPTIONS: may throw, weak ES

template<class T>
ostream& operator<<(ostream&, const Vec<T>&);

// EXCEPTIONS: may throw, weak ES



/**************************************************************************\

                              Equality Testing

\**************************************************************************/


template<class T>
long operator==(const Vec<T>& a, const Vec<T>& b);

template<class T>
long operator!=(const Vec<T>& a, const Vec<T>& b);


/**************************************************************************\

                  Customized Constructors and Destructors
 
Esoteric: skip on first reading...also these interfaces are subject to change

When new elements in a vector need to be constructed, one of the
following routines is called:

   void BlockConstruct(T* p, long n); 
   // invokes T() to initialize p[i] for i = 0..n-1

   void BlockConstructFromVec(T* p, long n, const T* q);
   // invokes T(q[i]) to initialize p[i] for i = 0..n-1;
   // q points to elements from a Vec<T>

   void BlockConstructFromObj(T* p, long n, const T& q);
   // invokes T(q) to initialize p[i] for i = 0..n-1


When a vector is destroyed, the following routine is called:

   void BlockDestroy(T* p, long n);
   // invokes ~T() on p[i] for i = 0..n-1

The default behavior of these routines may be modified by 
overloading these functions with a custom implementation.

EXCEPTIONS:
In order to provide exception safe code, the Construct routines
should provide strong ES; in particular, if any constructor
throws, all newly constructed objects should be destroyed.
Moreover, the BlockDestroy routine should not throw at all.


In NTL, these routines are overridden for the ZZ_p and GF2E classes,
so that many vector entries will be packed into contiguous storage
locations.  This reduces the number of invocations of malloc, and
increases locality of reference.



\**************************************************************************/

ntl-11.5.1/doc/TFT-time.jpg0000644417616742025610000051541014064716023017024 0ustar gid-shoupvpug-gid-shoupvJFIFtExifMM*>F(iN#8Photoshop 3.08BIM8BIM%ُ B~@ICC_PROFILE0ADBEmntrRGB XYZ  3;acspAPPLnone-ADBE cprt2desc0kwtptbkptrTRCgTRCbTRCrXYZgXYZbXYZtextCopyright 2000 Adobe Systems IncorporateddescAdobe RGB (1998)XYZ QXYZ curv3curv3curv3XYZ OXYZ 4,XYZ &1/# }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzCC ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ( ( (/x>j>6>"|Ox'Oy<[O$Q{IgOx $K&Gm>\8?߱pm>\8?߱pm>\8?߱pm>\8mo>-<t]}K;:myS5Ǘ5dMu, ~??ۃ]o?~??ۃ]o?~??ۃ]o?~??ۃ]o?~??ۃ]o?~??ۃ]o?~??ۃ]o?gűa'?n_ؽW0[i;F-RVF8}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.+^pb>k~6v{'Wmm|5bw0]2@Ogm>\8?߱pm>\8?߱pm>\8?߱pm>\8?߱pm>\8?߱pm>\8?߱pm>\8?߱pm>\8koI,t^G ՜Z:mKKI/Ωsgu P1qʉ":(}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.}sDq~?OoW.+.Z/O>^%u~b(%KoQs[E4$ I,F̮>9}xnqtc'߷+@>9}xnqtc'߷+@>9}xnqtc'߷+@>9}xnqtc'߷+@>9}xnqtc'߷+@>9}xnqtc'߷+@>9}xnqtc'߷+@mEM۷Mumoy㿀znt_o~;>#|/x[3t S|;oZ|w{q.hy1[\"}e@P@P@P@P@P( ( ( ( (?h)'㗄e{-+V7~9ҿf f+!~;5 >]#qsmocNτ 縂j/ ͇Ca0pWMTjQXB"<]jJuqo=/xq c*C £Ө3No JYҧ:8./>(_Ǐ<6cV>:&duH..<9x>$zZ5'UXgS,XJ1Na; )C:̿B:8̷3ք˳>JҠ3V1TaaƯ#X-NWKFup%hTV|5j8-fO똳 #?= ( (eKPP@P@P@P@?w_dW( ( ( ($wǟNT4P@P@P@P@?SE`SŔP@P@P@P}SOPP@P@P@P@?I h6= ( VT[>)&@P@P@P@P@P( ( ( (_?_>G|&1|3IW/|T嶙o|Oi_m=g_za |:.}i:,[V7+y 1YFU-🾋̰TZXzoxlN3GӕZtNx"GǰkxtcKD5C#pX iσ}~ 񖓧z,&{+JY` RcdrJdU^U<>+綵RMеج![x绶O5NPHr7Rj-›Qu=y'.YBc*Je$Q.rPM7)(hݒgK˞w)mA_'5~>/w^2͍πZ-#ԣqj2^!|/m{_,[ fZKρN> {Ge^$>a{yFigxSVYV Jq.QbjTa/*`TٯaYeznK0/p5g|>e9"ˋPρ_)/؆kswh3G}iK4/k-χ,5<:Fdp r6/q>PiJ&x w R̰quaWRtOebE,~mØfl:B%*(e/ F\zqjT*C #?= ( (躦Χg%վ&xZӌ})-#͈h% kr`L ( ( (*iZ1V|&mdRS%KDd c/5pL ( ( (<.xᏌ4]MCT4Ԇ#q(^87a{( ( ( (3U;mZK)>&|U֭iwm&|p#ӯ- CQ"#E( ( ( (4]Q2h![9oz,چSɏTOo%&HF@0gV(P@P@P@P^uOx}3GMm(?<1j3fFDkY]]H7n19T`L (?!U?ϊ_ɿ~P@P@P@P@P@( ( ( ֬%tm[L2RZokH^ Irg*Qeԫ}ZacT^¦+ V+rQ)E[)+=XDp*txaX|D65aRT*E*. JpO S~_Jo7wx ?> kii>2<[m{}|_,5/x7¶:ix|k*&Ke0OrX)Dvx; mሞ|RDVK$%u(Y9,ӍQ-c fng[>ZX7XyRxz ca^PxV!9Gkb$%X|af [T2̗Xz9U9=(e;xGO?C{ѴSƞ֯-noMZ ^t6aB|LiB80O FdJXySNrp,EwMEըUK B#C *xz8\0ԱUQoӭSR1S .3rj>U5`Db٣ŗ<d?ٗ/5- ~| eӵ;]ƍh_ir=晧gnm F" hW >"tjWOa:P*>گsM33*S* Ό:3c)R*R6ptܣi8NpmRGsCڏS7J<c g??l⾹xRǞ? m59<}iW>e?4zRŗbr S{d8*w f<3渌}hST89if4)GR\-JbpVUw3SYW`>%F F#jqnK/̡YBO ʫk;߱۟?Ꮝ<8xvM#U~ |IUءi]ҍυ=ex]`γ-*WfxֺżqaLO,].Ȳ6 /ɸir`1N'^mC$Qs1f[fW󬚆[K7,,u3 '6U < Fwΰ./_XF kz^<9JO+6Ki~gcs1>n>Hѩ7%zSX? y׷g>w3^FIumqca k^,_g܋#FdϚ@9k/|Qσci5]^{Ej%QOf~PY}peH>2PodyO&7 %zGKI״#RV\hS>̱$pGm7!X0 ^gtbxR4]xsgZ#bCŻ[$e|r;<__E??=vH!x~3$>ja$ܔm}wZDcup8յ KJ,-DG׼#SGC$ğfo wO/fu B,o mI]t9ºu{KM3|{3ڭoN(4^L_3PuYiwzFAM$_[nr'J)g%V_n2pkk"PZgw_zo~o}MV OoHY_;F;)Hϙ"X /5y6͐(ȿ5DQc(<1k^#.etìk"1}8k4ć]6X=3_?':lQ}8&Fc?q@.5յō3YhQBogS*AAd@Q ů"@gRҠNGMRX:G3/$_>%I-ŀ"6izoڼ;GG5{-͹mIJv~WXkk"P[%eHbyě:+II|-cܸP!w:Dio&D s"έm_gv i$Gź6,$vctbi~cO#aT4PI?#DWeI?be< BƵ, ps+xW>c:\ytQG ʐ3֣e^i:_֥,zPNtAk{mʬnnM~-o8JS' S6k$bH}RtjoUFV,WĚMuB)Fa+Kؕ#@$>oq@(Ŝ`3჏|}ghOHSL:͎Zpwldyb|7+*m _Nn4-U.5+]#e1O Ē5GT*Z(q1ȔdZuΣa\Z5ou$j}]}B}%X۽Rs,{4 //-9nm6֖O sfUȎI7򐇓n!4t%'tLwF Ah&wo%y8,M(s@  jZ631㙦ό=gtewyz6#ݽPvz5yE([^Ae} (.!O3fimgHwnK)4xO[nJ<|>$ZB4 ƻ{`ПZ}QOL$-BX8V2|U .>8y!JX%_9̥¶.jar<b1:ZXi[ ,yf's߬OB9F y*Pἒ*~4gar'LvaJ _N߁H/|eܟ3__j)ő?~X}.XfuY"?US歂S<&MC4r~haСO/1rha(ar QKau^P@c i|B~@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( ( {߱]g S}ʶFo4ϳiD[`Q\ϭS{j[R֝Xm˛|=kkOÑ<;A|ϝsۚiO_3~ђhv?OK-l|!+Z7D:_uே~Mf3::' jYu'eU3 ن"0]sYxF)RX|r4`.9aUcqRL&NT !9TԯJr_R+1ujן_ ~ڟg);߳_7]//x_Oxo~xsYu$k&m?FVLoMW,.fT ,%bTwוZY.'3|4*b.8LG=YBzK`0Wq(UiזuP@~AXsG_?gP5~P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@J*XKg/d?^ ( ( ( ( ( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( tQo)@~3ɚω~  5}e_oO :/|WhVOi9O(~OAZCo|S𭶽mme[o4pk6vwǨZ^,Ayu$4P@P@P@P@P/JKY78ת( ( ( ( (?( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (I_w^'H|4< Kx[_#QP7_ f؞_?z]ZBڿW>;_O<+/ =&_ \>)i +s >j|5hW*|2}?CX0u}t5v3V~gG$>~8~ <~Ϳ?`/߳EcķZEDŽ_a[C/0|E%uM4#w__;8S_ uh~_ _xFγh ׊xsLNm>+տS5A(7kO %k ƞ.w{'K G~!zt; KFfx?Z}7,r0џ$+G7Кwǖ>?7Ϗ*g? MS$߉_u="˭+y$. / ~_c/Ŀ i] ]|E]ŗ'|mᎩ,>ui|C7`!uKdhm⹜WѬ-|Ld-Kᾓ?YM4ǝgz_Ż6->w7TҠ_VV#'fXM^KV[o|`|mվ-|B࿇S?᜞Ѵ/狵S5HOehtG Z=sp<_ q?x'sO?ۋ_[]ᇀYx#MOZ~@l~#k u=;K5'SӵH?)ږlj~d>( _~xQGwv&#:W ZvZ,tuFW4fr{ei߲xï_S4߈/ޣ_ ~(cecž-<1h%O<=φ B?/_o?s<)_2h*V|<|u5}/6¯?I[xm-<qȮ@?hߴߍl;Z#8(y}WS'mucz t1GkZ,m P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (  ? U767+c]Wvc#_~u}3p)m  7~+|oxWge⟀ux=ڍ^M-4#P>xc5t|NkZԞV<1O >_@RӬ-+R.+kinGpD/ ̾7?l~#/ *#g>hu|*ݽ"|MKH Mf ʱpl/'\g|2oۿ_x j(K=CFL0Ed9d9(?OocI猿h_g_!~Ӟ4)Yּ!ހ?-+ h>P^JX[FQ$j ~ڟOĿ5ڇ?_ _Y~2MEyeiicڬ6/ ocRERXSzFo~0ͣ}:YcҒX;Y"t/?? G=g'bZ­{>?j.+Yx+}_:l>]:ۯPhhύ4{v+|E]IT_,OxJ|!|_Iiwwk΢̬Wd~ϟ~˟~~4 |(K?Zγ+#@i^moWڞm4jZ(Pc (?!U?ϊ_ɿ~P@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Lq)q7):]Kɠ=|&Aw2Wʾ(  ( ( ( ( VT[>)&@P@P@P@P@P( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9oG{2-W5kZ <+),v8DŽ}KOG`mƻOFu3?I>'3f_*lU@?U ( (cOۊW}g}KNJ5όV)k^07_i>þ(m~j6͆5|l?9WZ~6_<|o> j~?j?dk?#տ^o~={C>2-:^g|nmu {k|u?kP.:{\ԤQ}ޣ-džo}K)nyـ; ( ( Y%S ilPP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?1??u?J۳\зEO.!} Ϗ_dU~|"- x` zu|I.wß|:˦E1F ( (lڟ]:|K~&xGТ7^,rAȒͩ'u^AԵXn.. #g/ß[g?Y{F-cDy7kYNtۈ-q^]~$nu+PE*7!?~I"<W\O™;xUӧ|= B{{J[Wp<#h~𦉤kxoÚihZA&Eoc:VmociPAieg6G H@P@~B+?a-cz ( ( ( ( (( ( ( ( cs|7wkwهڎ/Ğ2>1L&mCZTZl>|2;c}ZX|0kYD՞-NJs¶Y9UX )WqK_xVl\֭^+ҧ xW)Q1V*gG/t=pUp0etrPjՖ"1tR:ӫK!}b~/ zſza}CÞ$>iiI.{ng%M|[/N[8n"V! bq3*Q S(aQчe؜FrPq4Ќmj0xXg:xg +J"T)|N!UU-k?m/)w?<94|< Th>{ſ|\_4?O{žѼ?m\~0uY@Ҽ?-w=YZ^ =y6IgX<}(Rɳ =<-)b*aq5*mE`=ʱSNyqs^*<N8, ɇX009M:جyaRTqV'cۋW׼⏄hxK#Xm1&O6Þ.4KUvPgy&}͸C9d5T1aN!N|fxܿ.Ͱړ4abpGsECKq>_ebK%*pUlVcpX&جY*ʴqY a\Ac i|B~@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@X_%~Σ*~.;j9cMlcҾW2vٳf@P@P@TÏ=<[G/G=ƛ\_xpW-tsw Ա%,O/ۇ_ |m7}ĿU6Es??hh0XMuzIh^)&@P@P@P@P@P( ( (?_ׄ?RohBQ^S~3S|7Gi~5Ƌ|PhAB:^kԵBWˆp3^qZu1_Yj24loaZoe^|6MR| O,kĘ +LPO)P^ysN18,YF&fKZ U_lvࣿ͜W hT>5> i^#} xl*:,׼M3Q6.*xl<0X|.*M\]VXΰJy&`_Ƶ -widLj2TU5ir)U1)sYWGb}<kߴ+S:Wŷtc#vVV3ZF]\} {[袎{rl#X:O WT1kai΋S^:΅8µHN5wO WWFq:t0.kbh*Bპ F*ӅzҕsD|S 2__>9a_?-xKfZ ?*?do@5=6K|4k?zŖt4!o6xphX[O gZgNG*!%?e s:k{Z N5Un^RFBRZT WM5:>iOH~%Wq|_d}GYQdŸ?kW7Zg~|<=[5tCL6ťğ7 ;Xj|~to^iWw3FSQušU<) UT>BZ+&|Ûc俳3 5{_*w]Lj@~_?jj| ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ({.W y*nVmEj>c/>^>P68$G$Gd ( (o p`tJGl/4M/wSiK/KmWU[M࿅<jImYh^|-)UYO#T>૟('_/υ;ƿwF|rKS? <3izGQm%J.bI( ( VT[>)&@P@P@P@P@P( ( (> ?f/'c'|Sm7Tny/z/x+D^tpiR-} e8NRկ*PSZ4Nx&sJqAƽ?_b!ީ]~z:?<_ZXݼ=ᗃ6}^L_/ÏKzXqajp2)>#Xx\爼3O |O|A2GZ-.ῇ<sk'| BT{[XԼv[G5eU3__ UbiIRF JFJ25`;8f#S :>lJ|::X Qr+խYnZ4ײ+,GK_& q/Se_~x>.ռmu_|eӾ7xC׼CEKu)EՕ<6:z\}+5fM4PV2Qpt08|/iRJ _ SszXKbb(`iUT&|$񿄾,;E?XĚ֕}Aд%lj<c 6}08Ugfz~8pJ1T0 ̳lnouqw0,?mr\+-%KꘌRUasNeUbaKex\ (`50tx95i_C[ o|IO\3=KτMC+׋"xC/xXFL'12̇gK?ϳL]n|vsJ*RKdx4hYTLv/9~/,NgekBKʲ\J>n#:̳,N6x ^]?TkfhKmW Gk\gSgSF׬4RfL|.Nhf+?.{POᕿnĿ>,񶧯[k\ݐ<=qUA~,|~,[x`7$ Bk[B `y&YmX,-/?7F myF*K]۲]\,Lpx^#$ƟtF(b<]{ii2;(ƒˍ89co^TOD8$m|DzV6? 63z%y5X/.OV{ogF+K-\J8: B? '_5fs-U678Iǖ7tzt< ;3y\5h.xM͍eo \ ʒ.JSR1ԿzGUmk+lӰ.o $ʀ0 cF4|Eզu"bY7sm'Xq#chœ`Ȃ6H^%ևϘ˸Յĩ(~P =+d:Ve/)j+cM16&D sm&1,.vq*Mw:y7~%-x1/_iMPb1۬!,O1$}IR;?;#xٛOŶ H* `p8xW[KDSssqn\Im=«CoyJk;Xtw[_jzbRV,bKy~]bf^3@a rW/8:Ott=-oMMl{&\eIq/Ϸ{ U^vWVvox"ºƇy1ȹ [~XmR7ïdamk|@Ԋ၌0AZ S(S.aY[z%9&Lֶ%㛏*Kw40Ȉm|3BլeYF~+OI 2PKR 康umJRo|RėIjdmMhcNħ P߅<..>78L>+%ֹoo2+QϝH,)>`xf̖!4RE) &9S;p2 Pœ<1ƚjk>"C\skZ2I-\[GnmGyXcyc*I_Tִe0xQJՠ."$"S8Qw#<_pu/7@ 7OӅ豳jb\]meÍL!c@`E&MfrmwYۙyL`*v OH_'VmRAǓIy7X(o-|bÃx~oiC5ľR*yifnd#.4x1k95X~օ Ϛ#VGlN(36:Yj7/t /$@6cl9" !kYq+Hk :v/Imť(cJ!MI8.sxKOx7ޜI`NvG,K<`bRh Hݟd~?Ԗ4EQsQ@S–V\UkPp۝K 54keږ&G}?SAlbKy0(3@_ rW/8:N44=)o]Qlh}&\y}(\H7Va xa<~Oxdy*64G8%͊HD9Szs Fq@C rW/8:O ϧ&=x=Է_m>68c:]ΪjHxRI&ps# S_< <j!M_e|{mu't?U+YKxS@#mo/W(jm='J|GeCG]3\@=1d\CDѿ|âY>^h`貁 by7~\Mm;/_BG/^TtMfAE̅rq(Ѩ/}y|~!|X7wfZ6v{XKv/* @76x>"., λ?hU/>~ճmJg[]_>k1f`u-Zsimj P^|aeY$b<9^A_ yt++e7މfKè?Qs\[kw'] iv? _k/WEt_#FGG^48?((qjpxzpRXeVoӯü8l6br/9`$ tg_(=J|UjuiTG Gu.9߿H&7M_Jo_/zǍ>x/'ğ|mk]Béx'Q7u7Նv[" 7Þ߅m F-~x3)4f+W NC?.2xCG$b2N:XⳊ|V6T)Ҿ/2SslK8/QG Px<6# bS+)g88L׌wk_{yyW5omm{;^P@PG?$z SPP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@~?(7I6V2_ SO/k1ȸɭ'D\)w (ϯ)O8?g+O|4>(x#?n>$o^5Ҿk;W?%߈:^oW5xv/]ڛ_0]~r~ϟ 'O 6bk'O ~-|3OotK oI4GO&k?<5Lx'þ ]:/]}GE||uGx~7ǿ^04c᷍y5>BmGI.Ag+MZM΂;@P@P@P/JKY78ת( ( ( ( (?( ( (? %E |[Bo|E߈[4xQ/Di5Niufg>eki0'> a0-?eaa0ԜSF?iVSS#zniRm׭SZ"WRY*r傌#yIXF1[E$'U> Nwf Ukx:叉<16?ZakZmnjZMmFIms4MgFӼS5H෴=xB) t?|CWhӗIu7xH5K-mti%Wp\ ( ( (_%gO,?oq@TP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (,C7NC~>xWx;o'ޕ<=ߒ0 9__ |?gy xOI𵗒}JR3 7`_ڷ_}O?gL~??O D߅ h~5I> &Cu/6w.Ҿ"k۲j_Pm{Y+DT fE€}@P@P@P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( (~?2M>3τ>u;GԼA{hsFW6.owjRXM;䕌ƿ?ି4?c~&5׼q?hZWE 4OUmJ]Lhb-`~ܟbᎩ⦷wǗ xSO|hϊ<]iMz~࿇Z.;φ5Vxtci$(߲#~/g.-qK GON> /;.-u/V&l-c( (?Y|8gCgOLb߇$R'/7?cxIZfz#~$qFQ#I$0Hwv¢"pd aaZGVU%MKA<\߳얺"x,aٳ\7q],?h?~1j62AwKe^RK[ $+Kid6Ӥ$Tdt;YH$Pߌ?]?S_O> x>x1OO"x.sǪx|o㟊?-˥ɫ|zbo 2j'_ůj~ҿi~.~տoZ6>g.g/[▚ {k{/Z|G [g ~$ῇ.C/?m)/>=|hw=iOZ+sX e&eiV@@~?n>'|1o ~+j>.MןPx' y /5O|s׼w-b_y5>ծ-knBԵMR?c%7=$xX?«F+_~ҿ h~/3R?h:f}'d(iO֊ů8O I?//ר[xrGĿ;O^ße~:EqZg{ÑO4 ~I_Ko/>h?O? uCh?:?~ߵ WE]x~^j>|i}?ge|Qiv~qEQc?[|B :w/ _ j xĞ)|YhInl|]OG¯ Q׿'G瀴oilj|Y[|$[xR|2ƚo|'ya{+]s7_GLOƽKLOD^'Ïhg_ GEVUA}gZvuV;[@W%~w_~\G5 ?|\_MsAOP+]Y|N4O xk׾x4sM/;OJ_ݮO Ej5x^B]Q:hpkQv~?h?Yύ~#|g?߇.(i S?ŢYhŽoGGItb{4O 0>6韵3|2&7?o_o?m| "iI(7HϠ'񕎛:5i)p]^~)xzOYFt v]O񞛨ߴGqm >i?)lK_ 7V ~#߇~wxWρ+| x3D`*ZLvQ$+&dvf( ( ( ( (_%gO,?oq@TP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( C4'$?/K%?>H__/'GcӰyVa/kǿkm>/x?_.}wo_N߇aתj^ph iaciwާ\OeP@~Mh7~̿~*|v|Zjߴc|jO߆~=O5O#ZN JB2[9>b~=xo>:Nmfk)L> 1ѿhm~又h_Gx0U_wMwcdI>-?a.~Ӻ:~'O6x3}G|:aw%]q|2gmúuOIoie@E|jߵ/~x;}ៃ.~*x7Vnou3iH4=\sT~~2oe->2xGfoM_ x[x< Dh'ӡ @", 8*?`3ͷ?o#Zº,_|a).CY>%GUtyngӒ쵄'EA GB@?:~&_|S^G|N]92Re` u+ZMZr!X<k|tsZOi[]*)Z2[]x)";ޣ~P@P@P@P@P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ( _+a ?_|K̏4x_TFN<6ʹn1@j  ^)2OhKGόF?lfq@P@P@P?Rڗ]?d/~(| ~8~5k~ xz| ^3׬dj~AXsG_?gP5~P@P@P@P@P@P@P@P@P@P@P@P@P@P@\OWO..N1eoڳ⯂gm-bR;W7cc~[z?<3zlt hZG;=B20oek+`n@P@Pο<5U!x> xO_>'_i6h7ux3E|Gg𾯠: ާkk \UMPu|7 h:cڛCOo |MM珞_ /m5P=FZh >^0SkwO'VM?}5a៉ ?kEǟɳ|JdjAK;r _ g ~~)~&x׾-?[i/ Mwĺ?υڟ%SSI_>P@P@P@P@P@P/JKY78ת( ( ( ( (?( ( (?4ho)?eO?h_K4_ ~߈)iڟAO?|8E?4|t4 u;_ Xㄫ,}LrQ\6V J"rZ 񹌗<kN0bYR3[{O,c~>|QķE~$xComsY ?vPɨnzowX)^>Up\VW1,] #&zU*K/ XkOF0'?:T+g UbQbXlMɊTF*s:J'/5Ps 38~ȿgp9Bhϼ b'5?hS|`+vp? 9#/Oښ?_( ( ( ( ( ( ( ( ( ( ( ( ( ()>$~_Hٖ{|EkoU[WƶT}<5y30dMDC=:~P@P@P@?@؛@>%AV2h_>3= ~ݏMWA&IHXQiyͣj:~"$HƋqqHTDUUU@UUuP@P@P@P@P@P/JKY78ת( ( ( ( (?( ( (?$__?িT/~VocgMb_8~"|I=?q= |[ ~tt+vnů Sp<6kRU|F1[Zx:>6IRacp؈/m(gX*YQ+)P29IEөkf3 ٦"Y>6wD:Ww--j|e(tO€Y> | h絴xOwgϩ~S): GuT(qs,t(1\q*5p*Xl,%į82n[#e =7R9S:cՆ^_2C?eo~:O~?s^U!0FUI<,V_*SQt::WnJQƽZ4V^g*2PnیӣY/gZJ2gk__%|;wSм[c\/ #Ú/gm <Kao1u ivp1 sHC7*#Śz>\jE4߅|[cwM毡+QIEzy57wV7:6w*xso#C* HXd2u^߆|n˻Ӛnۡk!Fe_h:B93< K?_\x` Q2JO?;k\Zѵi*I&D\n|bfE`~<|1fU][]>9'' rh(Ox237ڕŜw%|QDmdMQC-$p#D IhFM4mτ*x'ZoG 3vnu->}d@F $}$U$ OV?HmP.5 htLvd_CB 5vh(~7|8..Mi.ngH㫈VeI75# e@7#+Q?xcni^}A]ԴbIuK;K ?(S?e/_G+oMi/co@]+k[g ֵ#\+[~syp|bFd? OO!|@@@'~%?i!ԭ.m׉ͳ< shne%' !c7p |ENͨ߻kǃgBRLKK@r%b).Ȭ_{jZ;]|k} MX,<=ugp/ZxvQ[xEE+$摦3o ydd7Pg,R!"8cyd*$j]DVw!A!QYI< kA|A^; xC.lcҵ}Qq p"MjOd LvR=Ahz]6H=d ɒ#,U€rV~^\[Ou)':ho~Cpc5x|>fXmы*D\3ÿVD5[F&('*KxiK^ecF*\+~HE(Mӯ5Mi..,?4cgX%\I +M?_on3mno~nzoڷ}}e~l;1Yo ޽oqeh/Nkjai7%fhayЍ @_ _ |.]U?l/㶯ko -#ּy;+Yx/o_ DǞ5i.km5vIޑ:7,=L f2[e8{^kVO aVNz*Vi՜aJ~]:xn *2'5γμ0nOϋ180iPe\6N3W/y|FWx O |&3xv?bOdwV~+xiD,,#P];IWⲌK:^/(`>8̳ ?pbJ2O-rVkJT*fs 9ϛ̱n,C_\'a^if`OWq,=.BW:"VSt04?sA=4ItMluxP@Q?hGZ6|x ]S?߇u6q ^Úχqi3Gizt>k[*Q EL]ю&T0X =J:1XZ)K+I/oQMͺ ԠRJ=%*TxsT*Qo8Ӧua|{O|NmmxvA>/𿅴K[i.}im١R,JQ1Rn2+e*:RaڳO*UեN\9Cj3Km7|E+wR,<] j mn5^{}* F+fu)bWyfcxaҡ,sRƺ)RxFzqxWj M:C hP֣ucJ[ )*1I*(U:A+Ui99K_-Zߊ ~>ODd/X?zƯƗyl ( ( ߉9xsGcom%߅}U?&k>#RxvWJ|) h^ /<=x_K<5/ w3%Hд="LҴ(Ua%T$A@:*( ( ( ( ( ( VT[>)&@P@P@P@P@P( ( (?ۓs'?)M GǟgO|ox[Mm,<5I:9C⹱ּI[;Ljd𖙣k:tߝ+:a9|Ï~_OaOڻG:֋^k^ ҖBME>!>#6S ÙXzU~rJj\J41Z># pʫTḇ(KIP`3 Mk5hJ1Q O^aԒI$I$VI-Ih[% ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (+^Ziwz6v66^H[Z\O+(#HN|qmſW4sG?"^T0{6'+l=@׊( ({~,xg3ok7{-&kh7>lW56ӵg-ƝpIA_BWF+~q|񔿰niOw_xK@.{hw:/[R|+>m斞8W֚^4XUDETDE 0UUP0P@P@P@P@P@P@P@J*XKg/d?^ ( ( ( ( ( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (?=ଟn~4?nolE g=O|sx DI_h1 Xya@>>[~?'8%3?h "H|y\+10P@46qq,p[O<$P H^YeʤqƊ^I4Ej?L>DQ,_ U}w޾c\(x3ƚUO c5+;#{ֿ -?GK}|A{k^[7hkۿޑ~=⿋^/uQhx{.=B|mx h l5Hۋ'|yk_:F?k%x1Q~^ ./M_\x^(A4Zڧĭ[WW?w|}cө[~ U{}GE{K|<Զw:]σ~S~m>I4]B:wÿGo|}_/ hmbծ|1jֱ}h3^>]ꚅ͕3^\;v4P@P@P@P@P@P@P@J*XKg/d?^ ( ( ( ( ( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (?[.?f >mZGc'#s ďSS06n1܈<;O> k >O_%ÚG[S^7v0mc–x6'SdR? o*73o+GlJpޏ_Oލf-tAѭl.sZZ b31 ( ( ( ( ( ( ( ( Y%S ilPP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (?i/Y&c~dxO; eoWLjS[y-m-ͨCe<@~+W|.'Qa-pߩ<9q~؞m;?M:~6ǜtx7RPݐp ( ( ( ( ( ( ( ( Y%S ilPP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( (˾7csǟz֍Ne_WgWֺF ΥZZ}XX[wt$| ~4" M';3|bh_!^&xtO|J3x Ɩs$J@WI~2|-~?+,-|3/!GǾ&%3xi$)Y>ΒHFWH^YeDQ2Q'sog -,Z_?bPK-ƭF(ZLo4w?zb,5!?`'K[ydY;xeEd ZZE=Tgp$?ǿ):'Km]~ E6U|-Sχ&ZgKx\u? +^2|a]6^H? f/?>|𝇁)xkO g+4WR5bkkZ$j7WzP@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( (G Olcgпj/?oo|K~5|D` Sƚ~5h>?xk^*񷀼=mK[R-?u o*EGE gMsZk'?cM3&ýO9 _5H|-x1>6^ .n>0Wp5^?>"|l<{$yfu&?P*< Ui>oľ /_QVnowය |RҮ/|xni|c6ږPkW߶?%~/nV<7:.w{[|C!o_Oj`/ fO ou^z_o+ίtao xm/6Sথ.ComW+ꭩǦ..X] W~_SW}?Mh69߳oɨPxCW,j:[k@[Om7v MOR|7hόWmoZEU=M4qx*}_\Ѝ-}o?lό6>-X{ m*? cK=W\O@)7~?G?GK >?Կĭk~$??_zY_GYxg:oi.u]Om?kߍïR|ih6?>|R\*PxÚo+V:LJ<1j>8𖗦|O^umgYhVOy|;jύQ|f?5տ߅h?Z|EG>ZmMkz ~)xV^-5#H/ۋ 7 Q|4R?6   h~ai$7~|G'/m?PJ׿ ~:xz5xv@>B>=|$|'uOCYg|M7_^i_S]h4:>|I>׼#th4Y]kSOuW,zпGK2Y|- ߊ">>&]h^.դu8vngxڍg¿ i~]y?s ( ( ( ( ( ( ( (_%gO,?oq@TP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( (W _|Kuᮿx~.߳k[A_~ y_\xs6> ?5ip@g?Λ>$+m>cׄ~[wxSGFuaoqq ֥G"K?o[TwCX? 6fifib}>>g-i|=Ww?<@ԥo?{b{[K[3zveqMeY}4u%Ja;ğ> xW|2Vx%޷OW\mRR{Yga G acDU-9-? Z5?!ݶcm͡#=94h lg&`/D)oZτ oN~ҵK^7,t.h&xeFht$0W5a^慭n(%?Rpyo3F1D*#<3HҴKQci~d򭞙emaj$$Ey&$4( (9)gXi85/$R8E.쪪 Z_GıIyڧ~8<;y#⏍̷>rY>bn,L-|xֺv?p ( ( ( ( ( ( ( (?!U?ϊ_ɿ~P@P@P@P@P@( ( ( ( >~ž[{注kž'|3=뚵-.u{ko~}+,n>(]j&I.-<^cK l[/ZL Q+K 4>Z3JJ>ʵj*9pSTCӦJg^FpJxdVXT8v5\Qr*MۛR/O |=^%A/0t&k[)eՏ`oMEfE\_JZujc<8R,+SQXjb'B O qaRXz^6UlʜiX9ɧ*a U؉AiF\6"Ԫ_ѧR15c/5Yadj~oG>"5;5|DF>ixz~gqj)(¼n3ͨevOC5R*Y{VrlL^')ag,)1001t_,2¬ž]AruC璌m t< 3\m __[W? me%(ڟaI/?G%iQkKX=Må|Ga.G{N=j4wV//X [70n pX*j8ZX8IU,G1s*YVcJ V' GCү(cpҕcQ7ju09<sV?T'M@P@P@P@P@P@P@P@P@P@P@Q?l6"yTo͏~Ɵ/if>wZ0Ro@( ( (Ϋ^iuaik2X[ygi-:m,=v+i o_ |?o_>' ]x>/t/ ZX}7>"o}^7vK xO;x==|`eݭLj"~ԷYj6k~;KI?b<O|-?;ޕ|?·OB[-~֛k:h[{ /L,VP33@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( (?~_8~ʟbċ>1e_mOO-?|uK/xoźGß6W'};RE"[5+UWyulk&=|9αsW9 dye)Sen5`,\-JrVybquiV_8ѧS$ ([K$tS%ދmlM꺤m_SlR0LN)be:᧌ĸ-(VVz(0nj)8_G JEN5+QڕlEEJ4NΥInM}AdW|Kqgp/eI,)c~0Wq?3OUa?b&l)L!~𦙯~5-O5 vQ-Z0M3.[i 9E){T,[qUs<^37N {ZEGQ"lm,%8x*xigYT XUeV|=y_j- z_-f_Rx_ƟO4m? 4}BMvx"Ru]wN,WOtNyOGc8JrzuN96GNW =l40L冧v)ί73g٭."xo.!^MX*YgT])gsCZGIc i|B~@P@P@P@P@P@P@P@P@P@G-_._L8hl/=q0Yo/~@P@P@g7<~?NcQѼ SkTW|.~#.o?{'м3x 'izi˾vh&e۫F^+maӼY\h&>9__}SǞ mKv\~ieū_6\>~? |t~՚:Z ,>UP+ӋT>S֢If)fy<ק*rqN2稫O:t{,,!,0O?ଟY'3cU^Ms]7=|HxɼQsi|?;<*~#xKFC߆OWs;Jpqy"J4Cc?/75@ZEK^^>?V6Z Is̿eyCNT1Ln *0ЫaqYFl7֭WNpzahN/z.:QeeSF+RSQ^Tpі"QThެykTFV#!d?=ͯm?޳~__ Tw-ö>=O⽶$0M6Y.||;ooemqea/g D+xl=|#&g)ӕ8}Fd)׍IFU`iьpڣxu%RY ?-IZi>m1ĞGw~?[HD~ /hxZw⟈0'JbxVueyfwv%a|/,TgFfyLqO эlӧn<5'#Mg~ux+KWF_IԮ׮g/|~7#0X -tae*gw¤4Q^uRIF81T,˧qXEUL7N^Pa1.jӭ^I韌XxG67z5_ >67oz~Ծ\][wmbe/ ozݓ M=mH--w^0ij5xh%X?v!kŐxu#SnWU)}CLf|.Yp[Fǿ!k`!-܈ 4pF#m&3*؍x$ӭ)xE5YxM3ZҒ(y$+3P6e5+'AI[ZYLxչhp@i_V km4Fhoxo7ڜJ L.Icm35ș1Z3^u zǂu ,ȰC[nb[K] {EK$)nʑȎǝͳ n;xGE G-d=@Dža+]CÚͤ-.;O)ˈ-OTK8HdrQ|5u$SucOխ/4ܿ5ݭ՝l6u n 0ǿ!kӴTcuֲ\i6zlol51{nfm(/P{;eV>\O階jTeZnǜbo2IdXb@:|yܻM/|Ty>. t$xlڄ-cZ~,[|IkZ_ q\ jyVd̎4+?oM{ވ'o S E/e0[YCB"vGPL-լ3z'> q!Ӡ1KB+BߺK˛o:I cQ€mR,gگV1bu*xֺSֵT#$I+`ve80h VxVbiQW]Uљr} W5p鬞1oo?t2YɍCR7 Z0V.c]&<-uYkKrPEF\ZX]H^L;E#Eh# g_uut{RkߵeH'ψcoRE-F5¾DF8M]A4եU[;eԦk l& Y'C5"I4Ζ?j^ӤV>&uMU%B"(]3VҚB'04Albk0\Bo#⹒H-rI"B񺂬T~$6-k:?uDN:ts6 H-xgs'->+ŪD,{[״I1n_QX]*3*E&חmZ{\lb𧉦;\1KpYyC2DB(S8<{SXf1jP?mBm~ |!@/.,œkG5)aSxeIYةVP0e5|CI[[QM-o vw>(ܱK5Z'zygv]Z3>mo~ #q/ZZNVlȯ#\uZǂ5 (HA[/I.5{TVpD+JкʪPIa+Ŀ {ŪpT+ 5<75›9<5Z]vZK-STY̻I je5k ɦ^>m4,4[k:+wmksiq4 nEs 8`C7Ÿ$`2jZީ"'+Q)A EYYv,Ȫ́]UC3|)C_ሼY+PMԭӯ1!GSVQ;I(X%X-x=~]&? i6zyb,s MԻpwqlx}m3|)C_i&bĶsk3Mma5E̖v\˹k2s,3d<x_N^o6jX-Lմфc3LZ0 1pJ㐹7$_%t6Ed5X_iz2w~jֶ_2͕xsI524yeS)ԭw}V,#9̱F`qu:u?-y+u烧Q~Lfo*.< jʄ<#1o/s,㏆ZޗL~|iߊ]7@GOz/huOKKN>м5io0kAڳǟ⹮77Ž ZUO<+gjZ$uUs ( /4#U4G_Ӵm Gm55mj[t-CHQdlUt4\,1~^o ~О) ~+[GmFo W>"i(⧌};止?g;0oQ^3_/~ݟgSL>k~?e]w>6>:6<OQBFe3İKo[xU<,- p$eivD1>>fHdR*I ( ( ( ( ( ( ( ( ( (_%gO,?oq@TP@P@P@P@P@( ( (?G )|>/hU~!X/Ӭ/|EM{>|I5x[l>/RM Ny4|M\YvY`hJHaʵg b1U'Sԧ q'WrFX]jyՓ:1xE\M[)T!҄T(Frc z\ThSJ>G4 ?m?¿?m|Xޅ?5?k^-iOϠtk}^N4{ ."t3:>>aG VK 0өV؜# GN4ќquJ23 6VJ~f?K1b5CB#֋X{ N$ '4?EyXP@P@~AXsG_?gP5~P@P@P@P@P@P@P@P@P@P@WOm-O~|/n<ۯȿ< ?KRF+Կ7+?pOHRO o-xBF"VB8eas@@P@-|K3 6~ٟ#6 [ ~ְh49d$ZW/5/xA=Jk/ RjS`M54_{GGGĿx_n_㛟.EHe⛯sWWG-V><6s@P@P@P@P@P@P@P@P@P@P@J*XKg/d?^ ( ( ( ( ( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ~o-GM]$xJOmCԟDcgs3).Rp0P( BBBYrI'9$=ɵ_/ ~55|%oj1ߋu_36w=zYJռ9:}ޭX]\iuPEuu~b>>T_Zƚįj[όgߎ$|qPkx|E|5]2OinuM΀4P@sZO+֙sOC:e?#p_)4Nîj+oJ#c^?,>2O~>']ct~<ؾ>N_oah[M[EYIox⦹wofhK$q|OqWgmizNgong [6Ckggki1A(P P@P@P@P@P@P@P@P@P@P@P@J*XKg/d?^ ( ( ( ( ( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ~d?nGk8߱Ou[x"/h~*~+|0[MV;M4P@>_G/^6&qojF[G# |u]vH>ҵmStlZ(n%@q޿Zߵ0?NN_ S~!ߴ}X|^O?5EE%߈ uʹ̐l |> |?OGß^4ei< ^K8emK<;u]<(];^4ZݬZ(@P@P@P@P@P@P@P@P@P@P@P/JKY78ת( ( ( ( (?( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ~8o~ؿ/ͨ|9]okNO#yFh",p(I>&?J?~yx?¯hf 6L%~ܟ﮼?߄-_4/C߈:<-kzŮk_OB/ߟ@<q߱狴ko~˿KxkÚ~g>qƽE֋77 ?~ ( ( ( ( ( ( ( ( ( ( (?!U?ϊ_ɿ~P@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( (@p]A#@Ƶ{J׵[L=*[SY/t+M 7igi `E h ;B|]vj_>::.>_/xK~߶[χxCGu=_ FO“|U^8}O i># wT1q5/ßƚOh"M[NּOKyakE'Mu9u-1-^ JSq@FM~)tc!?k7qXh_z6,3O׮/oo+kX%Fv+-I%xᖑfi/wn%:}5-2MsH%"fwP 2|!qs;dž?'s5xZGGMմ=gG4/|o&/4GZ]𭖑C6k0XhK< oO7?m_+o=~o;|moSM¾񖩮ϧhn-,/oZZJW_M/?_io+] xW,'#%]xc\7CFcWH 5kkYk,o20Ⱦ+"#se$hO«I,uSxA/ŷ:OmKNs]$vr<}W_J7@/+ofӵ9"Zߍ"ҴGKkk8nHޭե6}BQ~Ȟ/?+~%f _7kpGG֭}oYiem,|@?5:OO7|%||]4߷mZЯK|fյ_ٿ|mq|04WVq_Y4w@3V_|~; #eKzTZm]L汫\RF'O O:kcSw= ( ( ( ( ( ( ( ( ( ( ( (_%gO,?oq@TP@P@P@P@P@( ( ( ( ( ( #?= ( ( ( ( ( (|,е*'yw|K>'|AE V5 _>mfALiƨ/vM[gw>t`o&[sGIxGGg|>"A~cZKwl|p.߇$u<WM~/ 1c|I?5-WTG9OGOhv>-O|,vsLnm/VzT=mgB?h"⟆3׾~ϒ| &=nji>V5 7WZvg/u<~ R4w42&_3Ӯ> _:ůg|F# mW~Ԭ~!ڃύm~9r^y |g\G{mS"t 1 x~% 7ேA?|6.F |LT]fívVuq7e?OO(Ɲs׀:|sixZ__Oz x'N{߄b^;-׃x=wHu%^OωG-_|L? ~8߮Hmڟ|@Ӧ/| 6i˝Pxkšf~N_S]O__[xsᧈ~:/G?_@<_Mi_~,_~ _wKk=*M{°"Px]E|Ue@_eo7{~՗W^-61|61k/X[⟇<^6t_kp? kG:l_3H7C<~;>-x8lj|CA?@qx{ķ~ Ķ +ߟt?6'+$~|d~$_|FL~~8s| xk|Y79Ğ7~x?}^¾Oi7vvf|@׉wi_UA.cNݕ|mltY|7M =7W_xľ wM#:8>x0< x>w wHn|k{;L/aKY8:̽*Tc9F.Zq5)$hT9UP ԵI›} 4(rya6G?j]UfB^>Ngk}Xx=gVmX9H]%H7Gq4R΅ha붨%NjW(4QeEI.2M+4sԥVTUH{hǞTʪ{7i{7$gՔ{`hPlj 9uZ"l/>4|8VTs࿉Z}uKsaxAeNJ|\$40lU|F_CQB ](hѩG^okN= Gr Wl ZTm|&<5yx#CJ<_i$_o|X=G㴞(/F g#i1Si~[pX6kmiO`p NIGB)τ8BE&+pU7)b*^&IJ&b+Υj?-V'=ujJ|%Ӌ(ƾV_|R?> k<__ş|>2|vf|!+vTӛ\[xGÚ?it]_YR{=:03F"9,(_{, ,1iEkxd0XXƵL[)K_PXr즎C/x^9# J`_t1ci"4ؚ<6RGZcLutV?T'M@P@P@P@P@P@P@~?? 4to+ ǖ>x?G`0ܰmJ< w7\ ( ( (?8?w~|0ON_x__u[ +ŗt>8b>5՜in&E~_bQ׭#cyǾ vo(į>9eROjZm%Z]iV}G@P@P@P@P@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( (?$Ǜ/ ^[$\oO?DCެU68¬$)QTBXj6X *Vtur֜'[,5(BoR2XV Sa ZL\ΌQ+!$l/z1=?%kO*podu Jx⥤kj) / Wݣ\_ii?NaļT t槌#u*ts=9\ٍrOlhʗ3pESOH~%Wq|_d}GYQdŸ?kW7Zgq?cџygSO2ǯɧ#h؃ _<;~,>*ɤ|GZk^O<[u ۻ g÷֣uX闆Jԓ쾖W\FW̳98*j(|CдSuZ?J i=^c8or,D1b02ⲼU^Wա\YU6rN[ねr:y7aO~wW' ౑pe渜]\UlxU5*:`lˈڃc "E$/z,G(Oڛ̀\P?_ jꮌԆVVVVH9EG5ͽߴ\C-qn\:n~`WPbo٘U[ bNII< @s]BRY= WppG#}wwm3HHG u!QqǵY mX)*jJd A M ͽ 1ɕ%ۜvlg냌QYݕ;,($98 ZwTr-G,s X8x]IS$CXL,=*2@8l?\  8 Zkkr0@XiGFTUD O@O[ _YD9o-bq$r22Adr94'b][wh`X32@9@?Xx.h&uS@3Q86~@o(C'oFfmso~6ӡw;-?"p<8QQ?]?ZITY#te]:0VRAs@ x-icZi0N3]N8wWӿv+wi+$E$]%H1@pc8-dTvڪ'gP1$v=*GP#ЌzkD0NT<B3 Oi1|Ah0|'~|QY-6/^;x~OxC^j/GWޜlb]FXk2|'41vەKk _>M^, ~-GcO ~lHRK5_IG$Z/~"xz?W? [:̩v7[|-nO_౟u{ _v! .c3W/-aZX<}RH>.ӫٟ[;;+N`-;*9@Օ]]WRYXd2 Ar3G5ͽߴO Ε"݌gn\#8鑜gj:{}fI<rI'@s]BRY= Wpp{s@Ws8id9!")2HUfc 4M b}f+\XApA 2476q 1ɖ9v8@%fTVw`3UFK18 $2q@?YXA$2G,g 7 k bүOnP_VUl?+{WK?tXoj/߳wO)WQu-cĚ|ZO_ EWmoQ(-$X/ݵ ]uW^a)a05LeVGXzX:T8УXZ ,RaJx+tV5hʦ[bcECSu0j8Μ"UĨNUisjpx s/;g&~?be`~ N{[ şhO_=Ś=k |کԵ=G]JS+c2YG*cq]HBxL&kʽ\~eqTXV"Xbj|V&Ztb+ev#a#^؜J\UP–+pb?j9k[hY~/ߴk>4bGxk }CqZxgHZxžt_G^*0*WXlc[^gXv*8}lEja[1!U5pTT*a+N> p, /Cˡ.Ript\f/X:KF;FrX?h^+6slMUN-d Rﷻ^| Ȭʀ~%A>%w7ֺxڥZjz-+RWV0]r_Jc@%_4 8v- ג.Lo8~o)3@67V׶+mwgq խ:EMoso":$RȌ9VPGJ5|Qɫֵ9c/66CK'V4PtQq@ |1{mE5x7.R—vomrN&e "?y77+sww@˥Yh.J-/<=w|} =RLm [;[Z]D\O|C<.H#2 y(N<#kJ=FΙ2GҭZf K{XZi.'1ʦYWwf<@x>eK朷-mոdHI`:8Q?xG֔1[ 1 E4QB1@|kq QI 7ooHiyDwP#' __1a\Gue{k[Cqks ohe_9#`Yy@@}(mNY<WUhP.(b3Rbs#U χ>%h:XyiZ\Ig,O%ayd<3h-o?τ3ВrI*/k1?d:cÚ_OWVe_:̟+xg+H/ߊk/~#^'#>_GO2]|9<xT-oY{ σ?f[K|,FZ3[z{VssZ@?dfsG?f:|ywk x[_kï 'ڍ޵o}[WO(G| qZPXYv6zfm ecgn;{[KX kh#\,qC $qF@ax>٧;4UZȈ\4"^ HGz ~ |(}[{I⹶HI`EuHEtaʲ:P 1{Eo;֦Ej:mC3,1H4++m*+[I ʹh:2dc_ SusVկLFP-. Em g?o 0~q-w῀#}&Z-R^i|i,M%Ibym^$=V;Z%Gy$u'FgwmгN ,I$9: ?𶃦hs4H"uA*H#P;@STҴoOu{+}GLycwms LSD+* S€<w'5zzkfbKm# IE2H@&cs@!¸GA?T3ğ uxOCׯ N IemI~efiuP5khޗXgeAul #4RI#;B:>|1ֵ WV'uJfҭJgr{jk|qsuo h+ou6c #. ge9QdTx䍆Uu*U 8 (;+3i%̗g[GknRQIp^8!F~c@~ :އLu6WoTFY>mm>(4/1Ex{ѵHh{kx%U'hA@yZޡ}w3^]OZ=ԯ57+9坉=hρ϶)#_fU6k>_<\y[&>P~&ƫ/~Nulw:<'ڌ֑alg1E1Ğv"S@2_DG"P+Ú|uv߅};@4+/+]/Fm!Ӵa(~ry*C[wf=P@P@P@P@P@( ( (?O,'"|]o؋_= 4xY<=@iF/kc/wĚFuYij~>%XN˓W~h^ g[ŋ^0h)YvV%fz ( ( Mca{zz\-E%[򭥔sow%ɮ&M^+iΐ!xW7<9ZW! H𿅼3X'9X[Z&鶉ZmqkkPB"P@P@P@P@P@P@P@P@P@P@P@P@P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( , |xMsQ8cvGI0w!'bZLDQApC (EHQH5Q@TEU@@P@~vO?nk'7oV]x;ž:q3Ww?]xU#g@N}7Ý[Y^*kKfUK@?(OjN_ ቿgh_n~:ky֋i O }?Y]xJRا>c/~I_#Ӿk? )\_|G֬ikWĉOߴ6yc_^׮K7c[xU/:l@P@P@P@P@P@P@P@P@P@P@P@P@P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( 17ά3g~?j}x/$h߲'Y^t}?jOML@P@P|TÏ^M?|U; zmBKkH[-o.z7)ƿPz?fx !xN.mvQJh \o~*%ŗ?^ïϭZ~8C>)&@P@P@P@P@P( ( ( ( ( ( #?= ( ( ( ( ( (Pݤ/>xtOpD:50[ V 2@@ ( ~? ?us&'dTP@P@P@P@P@P@P@P@P@P@P@P@P@P@P/JKY78ת( ( ( ( (?( ( ( ( ( ( #?= ( ( ( ( ( (dh} ;~Ⱦ?f vpȇ?~ż@?`( /WYƺGO??kf⏉^ Կb|=wٰ:ƯHGx'ÿujz's{ÒxO^ct=M1{I;|:odl<xfXկ!V~ѷE;j "m:Û_|9tBT!'bg?| _|Lg? ]Yk?-'_a>8Ιm3ĩDn}_JWl:iV}@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ({_EC?lڶ_/W<>';Y>x{Mb PP_nwL}׏uk&ck;K_[j 6 BmfK(汞+٠?|CdQ{YK-κn}Ή?T?xi5%̚~kZAg]Eu|j|twixV}%d"L7/&_|T/x$Z4ش־"UࡥÞ)Эu.'ռT}P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( (  ~Rw ?fO>;f~Qr>ӕ@ug;>~?)-~_n"[tSG_ڗ+$ b>Ƞk(?|'K|J K_F`O8mÝ&T opuo?W=AQO߶P>M/u ~֞]?o 7|HݵgžK+M֗lj?w@Wš sK  7yTI Zc^F֦🉵b:ܑXxAմpowOsc=Ľ+eS gXx, G(?~ӜՌ+Л E*UԧJu֩Jg<2aIFc?9'1\)bpjҫ?gcSπ?Oڐ^o_4v>1x CC֡Ҽ?gfx–Xi%:54 >7\i |VUt#Qy(Gdx[o?{žhz>g-)uw4<#gO3wx,izVCߵWū;;_JZo DA_:W,gY*( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?!U?ϊ_ɿ~P@P@P@P@P@( ( (?&>,E1(>d" дS?V7$$Ҿ|K> ⿉#%/|C?_5ko#f7RCC/W2P*YFb*N?ڙ(̪*u]i$G*ljtT/4jY3:0<dRX;YRʛQ0UJ.rӭNWX|VcS(:,F5rxG㗉|%7Ýc|GDگg'~GwyOdn>8~/c/?k÷Gf8ZEziӜgFj(Js38rR\G9*ykS$㉥F*jӧTOo5Ps 3\Ⱦ w|.Q?o_~#xMKķ?h?⏎?s jz^8;gkUW f2XD9~ ?Hk X^[}n dj8-aUZk0Jx}Stq8jf5K<5y|>xXJyY}^'օ.3 Ru(h4+d-G<>;*>@U̖ o?>Sw~#J/uk;> xnTeR8o&tf澙k^xG^'0N;{lgf؊iu%qnRPQRyKХ&QMRS0ܛs-lUm?m[٨QUg5B<8WuV?T'M@P@P@qma>#j֗_<jV:p/Ks,HmEfte7:~|<|?/?eh%~_MYkĿ9<5xEuX˭Gj9mmoݵ?O7S>f|d]? # yO ًk^41x k_^SikOx'/_-ψ=|4~aԵ5_?>!'<hV'} þ#ԓĖZ&o?VۧHj_ Eo +o~>%|"|j'u-Ǒxo@m|)Ğ'_z5߄_g?uAc~|=GzN?kZ ։gO*X@=p>S|?wį3;O񦛧| HdK RT9eqs궶z柩io$~س'6+OhOx>֭toQxO,<u+FExĚCkZ::L:ƕ{l=;n:+A5_~|p9?i/CMWzGSDk6 < Y2qǞ&#ZL;clWRAxZ/t_t {ߌ>+c')KeTM cZvzrN/㎵cudYA|+p, jK[DX x{R]ԑ?Bh ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Y%S ilPP@P@P@P@P@( ( (?o%cࣿP[GU~?W>,I{º+ˉ |Vx?+]*|+U-GVQt; Hۆ <3Rd<= .UM*! \1Y8F?ZpPƦymT\D"5om<%Xa>K bpD{,Z1L c_QBN>%O?,NO/xAohnlwZ_gW VqW G g9y,DF (ise9f27OꙜ+C.>l'5~_ TΤ Ş Y!]oڒbڕ8|]l*Ƌ/ <w:4jZr 3u0UE8)rhƾ"4V.Q^" Np\=EV E7'¤g NYe47㧀¯6? <% JIvh|,|(36i<EK>&q;Qd?q 8_¼~.TYJԱusyT8 'g voC fiSCؚl5Ry~y8e5p)KSזwXmOPu%xQVergsjZggsiL3I׿-->i,ѧ]¿w=: xź坮{~ 3Ϫk )h/ By%Ox*Hik:7ur.FЬ yFz$^l/O;f跀rv2ܬ_};,*3۳3 ڟߎ&~ҟ|][~پO |P> V /߳-Wx}n~|;_eiE?&c?vƚ> z|}k&m|J$4֟{kٵ?)[|;<Q~ο>*Jqx/#vJt=3ĶVm-n=luKBooP[˨O)?ŗ5?7C9Pl>3iVٓBė5-ɬMK֯$l"|yr~k^ _Ő#m xXú&;۱īhZN e1,'|%a~ {_y࿇~{5 7Qjz#ä7,4ح"0@*C3#㯊uOž-37a^V|M|5OaF&H}PisiVϊ@?h|2%:0|I<-i qῆ|7ǎ4gǞH m7 2׮'4m?g_?KGk3|K;|#6|`?į~ j>/WM/:h5>X|9#K߅%ضo<+sk |9-/V௄~!lؿ<-+LG5,'ĝJγ 5c[ೲtYM.L[s  _7/?h|?K CGկ>|Lw3g}?↧im7I]6[) UG4|is/_o>ݿ7z~>Zgu L.W-oMw$~ oWҵD`@nRGǭom$`L\Zm?zŗ/ğwڍ fM/4r/2 &[8.zq }DP PPhzg}Ww1oH{5ݜUC6UN6?5ϓ-wk#Wu :z,["Iwȧ_8,%eX‚y''''{p~)g-BM׈]m%w2jZF;h'y"kYt떞8vxx w1*,4/xUm,5^*H+; *4dEґ$϶0@]핟?k2CoY$l%ͼW!)FV)@ mW ׮.|>;xcbב޻ֆumJTxgH±`Ev3C4G$L腖$22B)0,A*sDC<'5gX595o ~[`^u4H2]tBʕtD3r NHnu 3B--FgR.[s'shu|#p8"7?Tngo.gn-.4۩-[+me{Y,W=zXk-t p5f 28[_ e9KO4׌졞fZKi*Is*AIfxReaIYw*4$]Mt~&M izmR^V/Ff[5R+SᏉ1g$s;[H^4,<:V}xZv8[+d*@=<37+-g5GQJ1xf') #G xOZ/εo ahW"?6ؚ#/&h߶].q=ݵͭžlGs<Y[s,6u"=@"uX9!xojzAY4}NOXxy&l\"\TuYH/I֥⫿EVs]yR/s\%T:;b0hPK$M,Z,1K%Ko$H3BefR r+6Mg={)s<=dTuֵm5ݦ ] *$e%ai~;cgyE0\jzǃfW %V~"($Kx%H6bzy_:ޟ+W" gN|%mez$g0ékwK#IEX]# Ě%~KI.S/ K2KidhΡt&%ew` WdGdt~ xEWeY[0YP'V*@uc^XbXѯ%Ʈna}PaHՉ.$G` }bN/otn,M]H%90h?cxyOj(tKOK/4˘/泞ń)nfUYAT T3:毠[ռ_+}^/n$4Gvv4FlY4놙(/O IQ!utP ,5[; CG ;uX5oY*$$ -`)`(oxOԯlxZUkn 6q·H?ElW ׮n|>( Ya5Ey#Hº.J"!i(ʌ,vg+qK"F:FP+*YA f<7x梀; k:IycT]I隵֕wu$)..}Zei$ƨo_ԯ&Pt;^Nam{y LڝՕ})O:=A"Ǿf7oX9!x=2N4X'.䷖OX䳸[Y&v1H 2]0߲}7 ;ؚɋHڢw`?mEAzsHl?<=Ѹik v 4,ѧ]¿w=:C꺎+xwR}d5߇5&S%P췗:KVM:;]G:P@P@P@P@P@( ( (> ~Xx_ k:|Om0eWV@7|7f\ϧ{Kc־!x[+;^RRgbsTEjYv(axjgf\Sdy=ӫc5JsU犥VƆ761)좜*晊WJdV  >!1x*UqXNOccqT?'b_'֟ 0{d"O4G_Q9֠ྕxS|Ke|kCjCw7/u[=KǞ9*e<1po ֖+AՌۊx>2l.*hTr6.8JU^/t2)2nk1:oevAV89A3eL\p ,^;/˰m\.^2xe:m(A U5f;32R]$ti ( (?+HK( (0M-#|At:=[Z=#DԵ+m6H:m9/f?ՠw c\s_xKFs k"o'4+CνxIl^1\Z47m5O|5j9xo x?5^1獴!?6V{|%S_~xcN_O| o 14/ kNK;imk떚yi@= ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( VT[>)&@P@P@P@P@P( ( (? 3`K '˸m B3|@/ۃ U/a4?"l]xJ|oQѬޢ[F]3Cm?o- Wf>3l#O8}KUc`p,Nj4YGQW`ã1Y6y`ZyMd:Rx,_-u ՅV bi8bjZsΫ:€ ( ( #?= ( (,S/6Owo_WG9XZ_O h~_/Oe)/ i>6GM*p01( ( ~<;_̟#?f_ اg :qߵ7i݆obf&xxwZn\k_dSn`6?>$WJ||Q|[MsτUPPxĞ<M%zǃaցo{6] p@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( (+WvO/ٚ#??4%y?gϴϙLM[J1~@P@PO ؋w:|QWO۪Y+YDž5a4gfciu1x_G.'UЭ(]J !֏|t(g'oo.M«ox_QUx-|;|{ }I_YU)&@P@P@P@P@P( ( ( ( ( ( #?= ( (u?/ødO| sַ^z]clf{_PyX ( (O {_Ni&?voG?»('| Mz#[⏇|y;|-/2 7IռCk7χo5 ReKெjPxź$_Iq_5?^dIAO(..-8Tꨠ3C PĦ{49H3LT,8rƙ*Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Y%S ilPP@P@P@P@P@( ( ( ( ( ( #?= ( (K. z6أ0f4. yVe?h{6tl (9?x ?I;^ι?x^Dυ|3]k^ˈt+Kfٺ%s |y|bGx[GɟNt}S_M6XNzGgNkk|Q4O Xz9? e_go4X.dDyn-k[ejOM^>) Kx:3M{{<tP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( ("Vi`2ڿty 1~s65un  (# j߰??|''n4¾>|C<+o^ Y7x~0|C]h3м;x@ ෿f/|x:'Ǡgo$~-kƳmcOO%/ Ypsi|G@5Fo$v;Hqs|BO|-Αi?6;+V$xf]:Nݷ xx [<=8έ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( VT[>)&@P@P@P@P@P( ( ( ( ( ( #?= ( (_K}h/Iv?Un%k*(`nyxEgtF%g~6ao[`;/w ω<ǒH_24\&w4̬P _uZPMz+ 6[ ƿnIyg|g> m<[O{1>->_kxc/La>5i|1'ςWW<|=+PsMuỻ ΰxw↹X c{/|Aq}R].)nu;gMtN{ -+IҬt/Km`Ӵ:l,,c(mm x#cHU@.@P@P@P@P@P@P@P@P@;_qS4ߏ,t_ ӾxwWH|׆m|y;Mx[sh3k:gss{cqq<ȍurӀ}YW˟ڷ? |W~6|uԟ|Ki~=sih#y5@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( ( sq=|e+J~׿?fñ@C Tt"Euy;S8[v2I"~[[[[A[[[AP HGQh(U(z/n'Tlt~Nд}KZ{}'NZҴxo)Q,&յM7LhKqO.?m]y?g&O&˘h]oӵ/|M>w#'R|U햍=DŽ@>3kGd>,ſJ<)gi{gO"WO^{K+K[V;R'ԯ!b4Y/.bӬ,l#༩egkj P@P@P@P@P@P@P@P@P@~B~_-~/" Ʈ"jUjL]iaЛ^lF.T5+[(kBZ:pVZSҠ7VM>X[c~{<ձ,Wƾ%|#%g#z_-EҬ-R5+[H(cV(VWӕlF":)A^ukU:pWW%&1b(a0XѫW% thPիRN0N2Fj( ( (>"??W?֡C:5i {/u@Y+iqOwowY5KFyr{'+QZ9i^OoW *ZiZ4(V<5)քW =L{xhb`a$/x_>xChZ? ê{ՠ[3Zu+rmp3E<,FJ05jTӕ)ʕ 2Vn&1L&mCZTZl>|2;c}ZX|0kYD՞-NJs¶Y9UX )WqK_xVl\֭^+ҧ xW)Q1V*gG/t=pUp0etrPjՖ"1tR:ӫK!}b~/ zſza}CÞ$>iiI.{ng%M|[/N[8n"V! bq3*Q S(aQчe؜FrPq4Ќmj0xXg:xg +J"T)|N!UU Nj(d?f/~Kmh(㟂tWᇋou/ȊM:Υi} V~?,WR8y"Qa2lN=CL:%5[ƌ%EVt0a'kW a+`'sJJRl$iʔ*REG+ PL׏_f_J|U~</|,ҟY׵|D֫x/{jzVuA\G~HjM]B byLMZmgN 4~]8U+Ƹԝjx\5*893\}|K\6SZ#:%D`CG կ E \8ʪ`Gk;?+HK( ((o\ۏ9?Ϧ~kF3"~ξ3_KW5_h!~ x_6oƉ/DEZh}N]ZݠҮ~&O]'QӒĐ_ z`JOكG%K'eo_IdDl:_Yk7Z־h~ӯ^P?e%G=4> > |.+o[|PLj,|Qoi c>,|B5u[ ~3ԼAA}wNL:E)@P@P@P@P@P@P@P@P@P@ Vb (v.xvΉH޷U߇.MЦMRDou Ymme" +4O x8xA񇄼GjG?״jz.iu[^Om:JwPPP_Bo;/_9Oڋmž1XO$AGD wzo ߆t}/QZ5ƧŴ euU7wuk\'}^te9miV3Bp5z8*]eLK8!Kю KN!Y."-xC R"h"8jC->4K?Ӝ*.,Xو7Y5ďJ_Iը:'RMp8ou0Bx&:U9,FYԣNp)pψiB4S(% pt׃p}ظSrrdԿ[??'ĭ?J_i7 x;g&ºMac池@{>zFB@}O6wm{@ ~i^aVxckGÞ'p~ya)c5x,[)`+8Vy4p:PR¼ׅq7,N G<8m^ ^kx6MT[~w<0UWF+ Fӌ޳9;t_>(/kxv,~~%& ~^|K> xO7_/|I"xjK4yuox+_Kw-dgm,'-[_6?aXY-*wKSWNVq6"LMtPpXJ5֢8d:[*(¬`>JTG@?j'j^u_|u.촽H&ߎu|; ?w;^/ZꖆH?O>$|5-n:'C"Z~i"ѯ:̫`kryBg'B WI:ʞ"peb0xT5rtiG-ק=㯆vqxFߌFX^ jGS+32L;xYdC[`0CK f5X )s,>qlUYѯ1(ʖo*1:S6XNt#2Ƥ뺖 !ԍ7NH h?gSlG~~7~ӿe_KOM#&{;]Wֈ$Cψt;u<'TԾvznm S MjU1xgˌ౸9lv3 Sў֩Q˖63 b1P3B+!%s7.'[:Y<Zq'`ͱY|9Wc+-OO[F"|-j6֡6xyUZXe\3JpԫgL'+kqrⰱS-f59SUH<%z5 J|#L2lN/.jyd0|ÿ/៍~W/|j>ּwګg:úvs cCƧLMgZc4kImLU|> ,^:0UJ<[ x XHBUha2Bxqt'D*l(VXХ¸U)O,0u+\ӣJt_\٪^<]q|QΏOݿ/ß'|#]wBߴ>W0>on4-OOWeعC*̳_(/>65Z1x/6caRS*BS5+Eb0o˙brԦt !eYNOVrjrxg6|Z59/ j5g,u^,6;Vᯇ[_{dsTb|>+5)W*+B/FX楗gCe* Zت2V.Xth`YB0ԫsT`74+>e !>S T¿[x_o %r xgk3oT._Ys]GUphOLSyv`1$B/ 8VNhC],T0ʳ]GS TJ1:rBSmu?i*ѡ{ YGO78~+_?i9x3> G]\ |nz~5kQXZS{{eξfv-O&nMP0( 炧[>爸rG:;*6:tІ fq6| a=|&ru~ tg4^pu_f_|<,MR3L_fLyJJT1xZE\_&xE.xW<'Og.Ixƶ5"xWh4}*Ě`rJy_[䱮~*ѼMށ 'S1XjnjV6픏iukyo<3۱D1+Das XeWbxV%ʝ~{Tg'9O>j~=`sS g fVjYvW*u!8QqVwmQ%~ fAi~ڶik⟍DfԵK+uYs<cFլ,pֱ5)quaę'?iC E11t]\$՞9΄;cA,)YYO qfsT〡r^cr'goo@tP/JKY78ת( ( ( ( (?( ( (?_ׄ?RohBQ^S~3S|7Gi~5Ƌ|PhAB:^kԵBWˆp3^qZu1_Yj24loaZoe^|6MR| O,kĘ +LPO)P^ysN18,YF&fKZ U_lvࣿ͜W hT>5> i^#} xl*:,׼M3Q6.*xl<0X|.*M\]VXΰJy&`_Ƶ -widLj2TU5ir)U1)sYWGb}<kߴ+S:Wŷtc#vVV3ZF]\} {[袎{rl#X:O WT1kai΋S^:΅8µHN5wO WWFq:t0.kbh*Bპ F*ӅzҕsD|S 2__>9a_?-xKfZ ?*?do@5=6K|4k?zŖt4!o6xphX[O gZgNG*!%?e s:k{Z N5Un^RFBRZT WM5:>iOH~%Wq|_d}GYQdŸ?kW7Zg~|<=[6o׿__ď'ja~'3_<}]o7dq犵? xRJz~9.#ęV`y[*eUK2ʹ#F1RcRѡO 4'pظ}.st p!Sf\/g%̲S%Po E5U|N#F~>0ɟ\oc G7/?ekN[>jZOv<k~O&_kcTdD|1Y5So@\F? g_u+1~_Þ%D|0ӾSYҴm/n,hx&j:twzu:uxL{Ĕ;@:g?_+$/N|Q)OKo KWO^*]ui;ڮejףR_^=R(^PҚW{Ko$ռj[f8J|֑+\%yਊ ]<: |=6ZT5}CKT;˨&wˢxS8.HO:SiWS.gMJRTsn (rt4.ƅx8ӄqY~_F1z6g`IN\R#y7Shx+p d8 .Mτ8f/KGÙ^IŘUG02|Qj.0ẙ9VlQS3n!VC5pk{)Y,)M3\^wZi®i(_M|/~zw7ëM3y߃__wF~ K[⯉/z/x?H.74? cӵM[J֩w^:5FZyaKܝc1k- `r[,`l%\҄q˳dvg_Z(UaVE48L,0)fy_S癖.UYjRm-˱Xcym,d+~;9 -}'o-㩵.~9W'V] 3[5;]~i˛Iwy\A{oo9t#cA\|LRI ԢRZ9CU:RT^I٥X`<;-Ob/ po3uyB0qpԌib)lJS,V(c0X4?O&_ <7{ 7~u k7PG_񽎷ڝ2 R3 ~ K}ay;RͤyxEWlRd\<e ǛU*n/)(x,}|'R\?*8Sf| L1x|88cў"ZKs=<$*BkhկOgZZ~#E[Lo|< Mg&M zՅ +V(W+gy63-+3:xbrXVo j8_GWO 'p&Ɩ2x*ᾭSV hR 8b(akШ /L4߳^1O|{kI|3/G~M޾3D4|Z7<&D=NMkHӞxTV3zLK2ep M!b_JUeMxR*,}< žaU|nCX,ltUU|U~Fe)Ud eTSq?ޭ+._կ4巓\[V} }'Pt}R9 mwu %ϕ5wٯ#<J+x?jգk~JJ>չChgSF+xlM: ̗p\[%WN7ʤgiIUq?s~}$&h'6# KFgv3gAEIU1$8{U 4WӯF,&?(]JaRmO7ю*Tҡ_:Mӎ8vեσL:N~3cz$\ܽ~k!Qc0ج3z%}?ybW`oثy~պ-(~_|Osd|Zc_߈z?n-#¿ ^M5WWҿtt_Qt-u o8  Vs:ٖ_:Wu`# TЮƤ!T)zS0Rq># *q897gҫ *% BWԹaf?e/ٷhT~94Do E>x+F?66?ImoW:xRճbaN'1XR#]Ҍ r*p (9Ǟ_% گ\/›W(W'==nHmݦ~VV6_ uyyw ?f/'c'|Sm7Tny/z/x+D^tpiR-} e8NRկ*PSZ4Nx&sJqAƽ?_b!ީ]~z:?<_ZXݼ=ᗃ6}^L_/ÏKzXqajp2)>#Xx\爼3O |O|A2GZ-.ῇ<sk'| BT{[XԼv[G5eU3__ UbiIRF JFJ25`;8f#S :>lJ|::X Qr+խYnZ4ײ+,GK_& q/Se_~x>.ռmu_|eӾ7xC׼CEKu)EՕ<6:z\}+5fM4PV2Qpt08|/iRJ _ SszXKbb(`iUT |6Q}~-/UA)7Bկ$up^K_#(t c<̫>l=i¥,-Lc(atU .*'9`p9&fe,: rLfKVz ޥLUzձ&n.%?5o%m^Q~϶koKg SbMR,#L|u-~=w?u}fįghm_OT ]^>P xF9P׋<+yu1gnLM_@^SHw o%AJҚm/YmZMދMa8i鲷VS_o,u߇?j AIvZnߎuO8].4Oc}:k~!u;?@>0 RG٢G/ x7-po4 ֐xk/#ei;3qc~"Alm5($@?r|'k ~-7n(Ү[/#Jr8NI/h}wlw6:{Bq ķOq wl&iLdD _u,e?d(<=Oi6eƷx[vKg6sO$ʷXYi Yvq.݀ 6q-4i"1 KÓXA2Ʋ)/iڝ2EZ(ʠ2©?|Z]# pEM< )beDBv WOi5gw׆.mnU_Ϟ~'MQGkv4.%%L)$ϘjPKiwt:wVGri%ݵ˅ٙ]&ph?TY>-PtNgMjZԶyo[K^mܖvV( 1Z»ARex×^%O|(?hk Ϧܯ$fmOL"k|lqG'0d~k , Լ's` > & qXⳎftcy2jz9gX!0p4/YsMEj3:eK[7ctH'ʻ zeynU+B/.d4.Q+#d[Y׆.!&@摏,Oxf{xŋu q%k-yi." ;$2SEa;)3C4+,4I Q4%Ш"$G]nV/U:O_22n|;׈H2 KēXO*ȑ Wt2ƦY7JiMΙokWVeTn"w'Xͼe,69ITY>-P鶏62^jRYZɨ ߽)^^6=)ᡷ#+(j(; ^x,R+kwƕnqU:[)H4a(a[\ϊwkoq iuxYnCorxR)Z 6`#a֨IMG_Q D=yAJ=CڍȖbwJM!aDjjW?HhΕ }2S4eI#=\!'̄Ҩp +@@M{VOl{<.4"ڬe "eYJIz|'[ w/x|Qsŏ^l^zx<+y.jQ]^Z\ڦ`%B-O wl&i!2!)20©?|ZKICeˍkW Oھ%ڥם5kՄ (ʴD@8P@P@qQ/~<{P7?_j_~ My5ޣ;χ4/,t;旣hG;#N8­YJ!FGZ~]J5jTRI|҄7kbFiPJF1(PNX<2xS֧JXJUJί+v|UUCɥ/<#=#YkXxJZӬ~G?e֫F9Lo< CM*8*y~2J y}N:1;s:0YvCK1V+NJѭiN\FQN0:u4k*^ړJtBQ˟J/K.f.enu Jx~&Am%?Qi!>:_5mr)JF"BB8ia0h®cӣ>].l94FKN8k9W<㈯Z*+q^Zxltj8e0ŵZ>Q푤xLS[~*ǃ#Ѵ}F}ZMƯKNb;]^'J*TaQƮ*L^aL~)bfxV -Vyv_ӕ(8fd *~Կ. ~0+echʨPKG (a1K0Rb*ah`_קC J8%SV5l2y3Lul= V7_Jh??G'?h;ڷĿ~!U߈9O2j:ᗆ-t0ږXmB|#JW9eJ D*TգO5ughUa*}O5Jx<$FO C<ޅӅhC  Q_RLUbp?W`1Z%` bq2ļV&ZC9?dk⧆>=|@7<-@x;AO<%tei#P 㯇^0OpZ|7R]\|YկMg~:|O|Tƥu|J;źCƿDm~(xZ۝^!:[1iTy09EP0,SNl^',4q18YS81q96yVƽlV/㉯Tk> ҿhO~xRW~.xPzhx׃|M>̚T"ʵZ"j֬7cƵZYܱ8KaFtxq8ZuEcbcFo )aBqMJrI<5|$+'_Wbqu\4Z^yml-JWs xHa|"h? |1}U/^Qw`|1kh^+?/ xB/xc_hlڒiZ5γ=^;|`a?wۛFSfm'LX(CO5V3:t1XUb+aRhѩM0ڌZJNR>lIVؚU|(V˧9嘿N!˥RԱPkV:5*_QO_>ck޷|s`keE~9|sm ?Þu/ i:VjS֡RP0)e1/cUB\Zjc q,YTq0L% 'W[^pr1,lF' N*O 3,uLT،},.;J+ KO,,A0-mE O{}58ͺKq4;:bkUukթZ:t`U)Q:T'N!N ф#qaSСiХ*կSтi^W>XjTRWIm_~NF_ÿ|VѴ=2=&s߆Z<'ڽ^*𮳮i}Q45-xO_1|>R刅*xYgJx:R[hT&l<)ӏlja)`hQVҥFWX5R5T V'Çt0&TJbe_[Veؤ~͞ 4[D<6;|~Z<=o|V:I}<xkWi"z:JZ?VR,Tpቯ1a xZUc7Ji(a#^Ò8baNsEr&L=9GVJj2ZSCH*_ֿh=g|yu໽RW{ fOK඼<֎w1ƽ&ɨrY<5|E\%jW"*'<5|$}S1ʆ&^0¹ZС&4taBBJ1X|deR`Z?89:> 6'JG?'w?loZLJ5Htޛ-[]GNU??[lOxGF͠ʞX;+aJ:W :XJ GSNX4ቴh5UK t<=XNe~jI`4xxTӜ1iF(Υ 'FZuRjqX'Uux5_;|um^iOg o2w:w|/࿅/MZOQOSTJont/Ka*j~uFSҕx)aT%Jg:T%IU)0iJfoSZ ϒ իЌp: a[TXX:1x\Ei=5ISc_Ͽf$% x4-׃n x{>{ +UѵkƍOַYkZG]{mi<Ɵ_Zs U 89kbG,e t x5eէ:51XYVx\f2#xj4'VyJ)TCJ8:J\T\\Uњ7 ?>?x_΀?LW [ķWV$x>+AjfTVV!hݳk oy}$bUSHy3߉h3Y@Hm ]k.4+'(%%]G;R~`q]:= 8P@P@P@P@P@( ( (?+O{PПK?O;6[>7މfKè?Qs\[kw'] iv? _k/WEt_#FGG^48?((qjpxzpRXeVoӯü8l6br/9`$ tg_(=J|UjuiTG Gu.9߿H&7M_Jo_/zǍ>x/'ğ|mk]Béx'Q7u7Նv[" 7Þ߅m F-~x3)4f+W NC?.2xCG$b2N:XⳊ|V6T)Ҿ/2SslK8/QG Px<6# bS+)g88L׌wk_{yyW5omm{;^P@PG?$z SPP@^|; |BtxGyw7|9Z_h֗yFte׊~K?ڷ53wj[Q~~/O'?h7|4G/ h> B{}SK{>}~̾Uo|^-N2HS?>$jf@~B+?a-cz ( ( ( ( (( ( (? %E |[Bo|E߈[4xQ/Di5Niufg>eki0'> a0-?eaa0ԜSF?iVSS#zniRm׭SZ"WRY*r傌#yIXF1[E$'U> Nwf Ukx:叉<16?ZakZmnjZMmFImsr>Σҍjl *ի.ugN*^ʅ//\~7 c:k|)Oۧu#k⿌ 3Դ+ofox"iiz4^i4+#_}.RЧOr\fWo%|^]Ͱ/_*x˅3 QX*ra2zs4Pk, p#2fY~G<$0P2=ObץYn#ߌg~ֿ -%|W5 6oǨ^ɶ tZ=7NKiOTzp?0gsќic8IޭJզҥG E֭V0zڧ%Z\&Gƕr|5':8pM T(Τ1B_(*)~]7 ݷ#vv:x)x¿N/~W߃&v?~'Ӯ|ib(:G]6X5;N eZ]ծcɭlH 6Y,#kmO*elҮM8ڙV?ieԖz9Q:T[u'iftr|wie*y/ Oa90ԣP 5*JqPPJ-޼ ]O_+S4^{2][|NOZ2n1t0u2Le(:x^ʟQ+Jt G3ͲZ9sa+b)iF'cG8w(սJ^?{_~R/'`~?U-W:_]sMëo |?ԭ?~4׭[3s.~|[o ɧyFJl ʲ̃1wJC K AJp%C SBW^GQՍ' tK'<=** `)U|DqEF3=W[<^iZ5F*)UO ?k/eHhnafݟ;?|)O X'Ꮞ5v/x\2[GGP'ռIńw7r ۀs\BU0>'Ƹ^ q L+:Ke|;ͪKեQ`k*]ӧ-*Ve⬋6b=| :|>tx񕞱|nKyk? >/W~ WOOBX[[iQhz_ե>&ȰX\NKxN2:<%J]j8..0a(2V*HRbkeC.ϧ9uVpIq]_}c _xFe̾4p1穅 m< )7a~OǺ;/S??1 #u{mĿ4?>{ai4#RރMyjVgp.3lMZv}q"E^.%|F +P,l1+U)cyeUrOaa.#r<X|*xg9Ju*r~%qA*f3x)ҟObOۣ߲ş*"׾?W= :Ũ Ə ;ukx.4; u5xیRR <:8t^q#,DRxJ48:l59x [:?no4|8je=ֲ5ei9kGa,n_p'J3eXE[P˸ K?*I naFX^" =LL˂xw9(깧&yC4)לE+8 Ҵ*b+V@P&)hC |RM( ( ( ( ( (( ( ( ( ( ( #?= ( |S~#ljK#akMj.E5}Ŏay oq+yυg~g_|6b~ |?[gh_RNѼhxRxtHkeg`] ( ( ( ( ( ( ( ( ( ( +?Zy1j/ZLJ>_g{/o z>j^.iϡZFi+]oPH4Csj1ײii @__X/C?Y|@5 {/:x߷2?E_~k>̞ .oբ|T◍?f_þ0NiN𝞵> |Ew+JM rY} |7'b} ?h}+@~'Ke/h)hm=m<g}Ŷڂi1<9xKtm;W,?Jᬿ_1 e?|#Ş =K/goG?>/xB-.w'{R - _ɨ4%U@PSQ7 +VsYW&{bTkdo4/C(k__1x"ſ?|#ͬki5''b3_3khgQ*8L.ON (a08L"y/g`:9v_`?w#^3~s Q đ/ W议-mѼ1}kz\][VS2Ο3"^ i&gG%KxG j*8|^+T=(MƼ>eIC8˕^׋^#S9saoZމ]=vzb~|o㯆QZ$^ g? _]jP]/6 ̈_ً^an8? ҥ^\T^G㼯(*ӮQ+86rxO(*k~Ms*2%ӕuK,*c(9Uuy!a *xK%Q[a|k*|L׿m[^--_x( hS&3?ςU<-> ԍ<>Wd])a2 WU9L᳹!uڹ> [֧`edXIgxʳs3/(FpV ]\9Z9~"<WBʥ,?/Mu/sitBy][rp6oY'fp\عgΜ1԰~krj>'<;FeQ3?ifyW_,χnYBwZ8aOcZ.GJ?f=O:|QIk:Ɵgiִ#Mkro?ZxjW>:y~Wqv1xlꗋ#O8*Js:)fg^{Fhsy]Z_*:X*R ÜYC )F_]y6SeZX­<#̲nccpxM_֨mm᭭k顆8壊&1h&M E ceԝY=Z*9R;rzޭB4w;U_s) xL _LxḲ%NvO}wQ[^$-mp֐p%+VkxvHZ&행h7RIhQ7QtR)Ӌn0zǖ-hJ\y)Yi);&+P@ {&!>f@~B+?a-cz ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (2h? ūP@G~|7:~x#ŚXAz}SOq7zv]\Ζ Mq<摘м?_K3ilGд=#K73urm> {H \b|i7H@P@Mf~'ĿcUf]?A>IOg?⟇h3mt>?S5%m [|OQxa]J8|%nGƲS[+(pҢ:8Zt*"r# Kp> S:UqasL'S TkZTeZt:1q )a$we?#cE 㿊|ukw o\:ew{1W_aTiT<>*"#N\=J>OG(xMu)UO(V=\UF0 |YTʣ<-*+csujAf\aJ*(cbUiTtr]un׊n_|Mn[:ſxHڬx~_?h)i> ׮%i-{0Ӯa/իJ0N8ѭ:aZ|30V<=LVYbi{Uue)T1RҧZ1V V…lbK]Ju0iQ҆*+o 7Bk5/ |i~"W~#~kAiÝ[uK/xVo`Ɨo$2'xWl1|+V4~`xM:ٍjmTqXBS_n԰qψXh`xm2/OhRXZĺmht\hNc8|g ' ]"5{oo{߃? |\O_}hg| -<>-:^gwDz׎uM潮iiqOP8%,3x<~uôr?x<6YNEq)aSO ʞ[,XRTxbx6GR`of"OZ2X<}k,f8JpUmk D>+`~ҟ ~~6I |% +R7 ^ x>3/tw·#6|g*q~?ZThg}x֗,fg8CpUJZKeb1ؼNfpY\'φ!C)h֫S"Ll s4)JtA~+~Rh?|6~ <<ךO]+ķx.-_AY_Rˋf#J|+8_9+ʾ_Ca#-ecjaҧ Xj~Z:Xq|/bkOsqY'/N4iGRt+f%NXh`sл&ਿP_'7a 5Ci.7wĿ~I8隆m<1_#@—f-mOc+Ehaplb|EBYVTt|,B\֎?(CKFKVȒ:*Y dY |&i<2X)|sӾ5ixQF>D>$i]"]ZZ׺i:[|`0lbdy%l-,U<[qֶYu x|0U*V58c+p_'˪`q9+ Z5s XOeMXQOڼJ*^ b1AǓx>,aOYi x[<5SqLx{,t^j"V4 xRlBg,g 3(N?eaӧVJpGVT7JsXwV+:5>yµXIr8ҩV&N^xkIJG39?ி%,;c㟃ow:ôzZO50 x D\fZ]wpp>K®&x ۊ?4PSLω1x<#CRQཤXxVAWV6ug'+e )`祈Opަ+ݝ[;G V!cMO%ؾ`>1MX\|徜ֺ浯gk}tj:j*Tܔd~W(N6m&<;?i'LWSgf_P|A{Rc-l9|3iW"Nu^z)*Q쟵9jTFKjU\R9aʧ=+ ^"xՍ:o 4ʝZXVXKMa^"tRNTJsK?Xؓk 5E|E߂όM7χuzx;ĺGcu=ǡÑe1MX/49y/5o5k_C~ $}骜SrQ\8ٴh}Ia@P&)hC |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( (2h? ūP@P@P@P@P@P@P@P@P&)hC |RM( ( ( ( ( (( ( ( ( ( ( #?= ( ( ( ( ( ( ( ( ( ( ( ( ("__{$Nӿ5O׏gB K?z_>6|5խ׵3gn-te67"v_7! m_E6/րy Hjsk@<5M 9赠uCZ: _So-h~)~?οhoCWcZ?_7! m_E6/րy Hjsk@<5M 9赠uCZ: _So-h~)~?οhoCWcZ?_7! m_E6/րy Hjsk@<5M 9赠uCZ: _So-h~)~?οhoCWcZ?_7! m_E6/րy Hjsk@<5M 9赠uCZ: _So-h~)~?οhoCWcZ?_7! m_E6/րy Hjsk@w%*o߱(,O ~Ex(|K?QiޛO^\5ݞZIo- |RM( ( ( ( ( (( ( ( ( ( ( #?= ( (ɾ\;7}ϊmdȶG1ýʂ2R$bd@P@P@P@M]\iq:Z\|5qqjȶi?4RMlwiʳHh ( ( (%useVw\åF[M$oRY#mFT=j ( ( ( (ɾ]\/uq=goq,4v֟Sokn#1H- xpE"zP@P@P@WW#㦇d.'oWOh%[5~0tQ48$" (h ( ( (&usg{Kg-iY Gq/$O2gl$nր=f ( VT[>)&@P@P@P@P@P( ( ( ( ( ( zZXhNv./MVOӬ/K{۹aITE /Y~.h?/Ÿ8~eS?, G4EO?^)Ç\ _?p#˚? E'7ߋ-?3̉t``nV8!@=s, G4EO?^)Ç\ _?p#˚?{s@/Y~.h?/Ÿ8~eS?, G4EO?^)Ç\ _?p#˚?{s@/Y~.hߎ_)  2$Q7> 1UX&hЕgX+@ _?p#˚?{s@/Y~.h?/Ÿ8~eS?, G4EO?^)Ç\ _?p#˚?{s@/Y~.h?/Ÿ8~eS?, G4_9|٥}&0ErHg31Nz`^)Ç\ _?p#˚?{s@/Y~.h?/Ÿ8~eS?, G4EO?^)Ç\ _?p#˚?{s@/Y~.h?/Ÿ8~eS?, G4~9|+Y0-iUd4-<ͿI_ xw,'=ݏt?UlE8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oe8'߱7#_oeoG,xCSKoo>$|;xL4[hӬnu#@ˍJh^[#NyZ;t@o ( ( ( ( (( ( ( ( ( ( ( (OaWi߉Zoū[=O\/c #^X[[?+P[ KXK]J5 NzNF+fx<,ձ?V*0ЄI{Ziԯ5 = VޞRfpL)VslsVcqxӥFRckMƖZ҅9| ƿ~?~߲lj?g~ «ovQ>^ӼG U݄o>GNQM032U\lV;+ibqTxnopp5 kbr|n>01XɃVb*}W ̪¯F/0P͕9}CK'7j*Z0J\DQpP@P@P@_M/~~ҞW_W6o_no9þ*-i~%֭<[_5G5$#>#apYG.%bviK], (g*16TT!:hCzk1UKV+Wu} _ľ%<9 xWEa,:[_5\[$N׊p8F +bsb(NTPFJUTԧ8p\dM,n1s Cax5XVbqCB7(UZRH7JKFj ( ( ( K uaN|*ASM;K['ټ-O* U*BW\Dl^,F>A*x\%)b1 XJoi'=:ӄ8կ^UjǾYaM|fe`*28LFay18}20hJx<+J|9?g_?HE^`vk}*I[moK-l y;MKP,e?b2԰V,"%4fn5©5X\mkڅ^x)IG^. )֭Qfk*sV3<^SN5c Ʀ'ZxyT'Rԕ89rCoۋ e||}#wSúj_~Z|Jgj}eix r\*)+]n-S 焴k 1kOy閷yR2,kͳj5*6 eז3N08:x46XQ֭N>\5j|f"cK'jRFxuЫ(ε\t'Ia>L*Ub0E W ?.x;HX-"Qo&Uo-46 [B%(%F5œ5%G I*С_*4)u,6_RRViɚSV*t8тZQqNUiPU*M֭F<iR7T7??O'F|T=ρ,{_ G5(4-sXvv7^-ﵛ}&BSa}O_үR}XUL|Jc1L`pyv6uYSVSl} B|15!̩s*שaRa]QuI)UTrbӆ"x8>j?g{*ⶡg |7)'45WDino'Dž쥶6[Z];&ZWc#TxH]jZ]sV\NMxZZGԵ+'[4j([ N'/z%(pխ*iӕZj./ q_ԪbNJ\ /0#xƵ4g:DڄNs8ңFQlF'Zta!STҩZ!:Ы bRisN:jԔ)QJJh҄թ p/.τ~҄ekI8T*y UqpTTjX?lU2躱Ҕ1jJT :q(­,."է G-9~x/~ |@4Ox|]xkR<= NhZYjzFu\C<24nc8̳˳ 5l;a1t8zZX;8ԧRǮOJ愒^Q$:u!%(TR1JeNc8'K\@P@P@~|~U/ j?ÿxM嗊ljo4ZN7چjmi˥Zxb{;mwMFӊ>}hF6`*եt( Jt0%ajԦHsvPխ*^tpҖ"8eOaFXxTFu^3QF/g^ҝ*TR.'տ>4x7v5a ckئ xoNNEsy[&i 0],uqU\'JYn.NS:fFs9ʜztҜ#.hciZxtU%V]AVVj+RUN)ʕZN)u<}௅^߉'Ѽu#L|1_ k,6zvZ\]Hv ,bׇPab2hъmSRj)PХqe \-N'R Z!?KOEEԫ.XԧJU*kU:4(Ҋu+WR4:B%8 ~_ /?k4߅5OFxSTtkVZƥKWFmGGŵ[/S7zm Ydwfy.OJJy_C0T`S*8b?m [V\ L2®B0N#Cթׄo īW JI4 ( ( ( ( ( (( ( ( ( ( ( (?hۏ_ [O?xKAѺ5#.|D>iL^&7|%ju&tlsͫiֆ'e^76z~Yu.-f9YCY(Rיҧ`2TSgCܧ+> O 23 U)a2 bX~_IW~m?X/(oCPΟb?:~k$Co8lo#WqVP4.b֬|'x^}[Ğ'm_WFU㳕x5rfid$C J1Tb`cb*Nr>cr׌~_-Pf9ctٍ,f&'uq xbxJ{ /3*$+qX/U揠_A'%Կa_??/r_ < (վK۠ 9?kz:faj%gP7ÇXsr3.*.:OdQXJG3jJiGؼn*hg.)K5ᚙ[e:T5p4s q4(֞oW ;shtDl;P|SS᷃z\IqxuY.Mv_di4}J[wW)Eeo`y ʳ\#<1#'YQb>G,̥N 1,or6Q0pʤs)֎.kJE*, SX]GS)Lt˦tPwcit꼪żrrkMCZmYNZٵ嘙2ܿST`z˗owOM ( (>gKR~|ƿ?>|8|G']vڍ|ImEn`ׄ}{]N.m{N&y^19w-ի=T10,<"LEIB*pJxs=, Vgx~Gճ|1ԥGJP3Wajjul5:W8{O?~:&xS?c|>&nS9|Y_H)mZ>[W>uۡxC^40=ⱑgYf0Y?aop4hceqpuurcR瀕w($bX|2trL.+OFZ՜2&cbqJ9̆6~yaU/Vfq0ƿ'3#$֯NM|%iw|Sh=݅k>X{᰹~cFn3aQ:1xIB;/ĪnQ' ЯUn_4o C'ׄic Z58Vc%G–&XLUѬV3Cj}ccia'uK+hmRmoN3]NGs)$;%-)/xb)Z4;n0B?9omg:IqUNr8m^r0~'>> x/|!\h$CSH¾=/|{Z_Mԯ-FIXW8bk;8 RaRtܧ٧`o(8MR*œTR9^Gc tjաfzqSseb*rsGpy&s 3\~8m,k4 ZΏ߲ŔM>`G$P8n%Yp$Q*7兰嘚ppp+ B*Η9ay>ӅLObqǬz6i8׎>9q?K,F!bUVΟlY j2gu= \>u|oh߸DS% 󅆛j'ye3ѣK2J߃8XPw*υ2sJ#*RI7I8h]QJ2(thf؛sڞ70TTNF*Hݯ=Р ( k2*")gv!UUFYI$N9Ru+V TBu*թ% t.S9ь!)I)]!2b&7)I$m$z+ l(_SĿ'{~?bx/|7?i|9?ּg߈ OWgtM+[񟋼GZYi$iu&`V+j e38%rKy%RqShe5qXoe1:r՛Sndx>)KO.h֖M,`Փ3Jp9&jR_/>U > ~W{c=GŷNj[3P&x}S^_xcN:׈omi:1O LY~12qM[0៻(հ ͋ur8jGqԫ|*.̰*7S*YԧRqeү}Qѣʱk93NnAu'}J/PkhMVO ^yf8YIbI&G܃㣝|3k9Q1z_W7pbw\ڴύN-qiVL g fZFO%X?%/b_l;O7e~4΍][C C/HHZxY.$c33R~W(IxRW9lVNy.i6g9rRrIp(5y((ᄢI$ItG̿cW|G"\yR5 ( (#!'|9#?V^Rn G< *{>-bυgv iچ]I4?-jZu?5("pHU|U5M2  ^ ׼e'W>ѕcp8p>\0E0lfY>' *º U(eتXan?gG20YX,6cK\B^&0^¦/ LʮI \V#׍?궏x:Ai:msoqW)dxCWF+ _ўաZHb䷅ZSS+Y̺^~0hq8zпaqz5j-¥9BTՏ )'j=~R Lc01ׅa]]m{U3ʣyJ)$vKEw?Ni'H~߰>;|Do؜|H{[[f%,-l#Y a} xMZ]xl #J؊|C”[Tɀ=lץ ifxzwG6ɲ\ƌڿ.oNKe2O W*:\Ah;btVXiQT OfJԫ/au@JػV~74oړ%Λ2*? |W<_m/̳5i]~ 76:ΰ~myej<őVp 䘬qڡfR)0ף,3$q{\IU=.AxY& M{~#|VKG򬾖UcslM_de`qX!e N32jXҙa@P@PP_ۃ/5 j_uoc_➰ïoDnQ7:~zU)Ռ' }OɿK+&ثG⏅Wn/77?X)I|!O[ѵJ4c}㏅~:o[wO _zǹ รCכe_1Ip4S\ eBy<sF0Bx4ɻ \fp[C řfg[q5է)Yeqx\c e?>?sx~-S=/·Zu5ϨzR^~~15m7ƾ~ۖU&̲}l5l.2ʬޝL6i,>wuŧ 2_|#syIm[ÖC| <]O4]tp"\3qV[G#6*}Cq&qqJ.1=  R>/ \psFIJ*=\"5eת~]_)[/%eՖ5,DZ.2XOɯ<↏㏀G ]SߴOڇ< j:|*`M ύ|{GG<du"[/_౼EFI;\^5Ʈ<k`Y.$qtpxKapD񔲊sQ˳ *y]5`]< Tcp8cw9=>xdW|,5ٟhOGf7z+xGGR7494$O|L[_x3W[ĉ}f/ʧ7q&c'l\,e[/b!WF0Yx8|>/87/xü"֕5܋% "WQӝ׫̡,-h՞*W^_39N~4?e/ǯ~ӿ?Gu7Ӿ3\|/..?|'#\oC8;7_ӵNi>f* f7xO)j}ea2LG4ҫ`ayn;,qk{ùtqr̸.96j0W ԯ<^' Z+ :&]Pe VO̳FU**@0+mwmv}?/8B" q!cI$ŤPP@P@KhX_ٟT>â|]g*k;+xJHuv>,ԭm'JKf}Ljg^k*8dxcS/YQ,..| ם ]%JXSuiSr`q'Obj14*'Ejb*kTXPW:&jgi%ͽK6y<,ixe[N2fEZ-(bq'_cpUԅ/iQⱵiUC*x9y6T<0J0!rc+aC,r=z|O -g~j;OCw]t߄>0W++xR Kx_E"ˋU+{Bxlm<<8Q Ux,jUY++*3j0b9S<^5(}iᲜs^U68 tpyW.G_W<&+-`#?_؏ 'H_WGo |Uie\|2|Y/Źux-OמY5. 5Wю\/_YקxCvWK/o':4~:k*ha0l1JQ$Ui10Pe)caiRjRU 177 7H]ߋ_ |[Cæwh6h~xB߄|AொZ x{ž%𥷆'T_`S㾣C\:uWX69pYt1j0bV1vePT <],M<5,F?+\3PW3J~:T1R\N"0u%,[kGտfeidh[k ϊSKCpeև᷽ڌj?&ROaZ4o ĐyC_8 X` K2aV ^|/1>֡~X{Xp/mC-?k94Rq|"-lœ01I_U~:e;ķVw5g "OGKO>= FNz"n[/Qř49Ul]K 6A`xf RSg,Ы9ԣwGթ9GգI6F8fiuU><֩RU!G˰<4)ƌtcNX0ؼ^+ O0B9`匮1/3JFpi/v>G?kT ?wO~9khXOυ-ȷAᧂ*Qf|yK4L:f-:SXiTij4L>O0_#'[<ڒ^x:o&tu%gԫf\fO]c,:iN TZr18L4b4'<-wÜO yapXƤژCT=#O4qPNqR&4O9[>f/ا`|R]*Oh4]=dĞ:g/&X=Lc"U35iΆ7tayF bJ:\aM(QSQGS Ԏ'ѯ?g'sp:8z5SsN:TagSWpP@P@; |+-?;-<i՗WL&jMzKXuJa *룅ᜳ81)UK|ˉ0|SJQu! UZxxb{b2LMZTVq(FUM}I(.#.xb'tpٗ~M?4|?`Z6~:~>oH {Qд? VlpOt.|kߊ:><#~!ܦ.>2LG5pc[_ ]I㏎uxw¾}'.|W=sOV[˛ .IР5;m>>.oC#ϸ:`U n3W.N\,.1.=ac)bkЧ?̫Ac},fUml%^ka֡Jk7MNmQ)bfaVt&ƟU3)/¿gwR6_^Ҽq=STkhm2_hڼzE{Ow]鷖ip;*X|^ :NUO/\֍L QL +K0U+Cz FcF"|U2)8%m M <V3:N5q.u)Х =XbO*, K[~Կ t߀GWWwj ?nڇ῎乷}_heN_SiZx\?892e/o[GxC| H|_Set߄>/W++ xR Kx_=he19j\™2L62aq$(Qe\)ʱ?VF!bq\m\aJ59 gƜE<=|6SΦ2,fAapG Y24pq88Sbf S?h)c EWo*h]J񕇁=_>W/FRԵ)ދs lqӤ/L)qM^%a2FT*Ƭnw0Ys`eXFs~_g%,vl@|52'ba:2|Q^ `1XoO }+#O.- o{Ki~DR|;N^>3Qw|i> .Xj:}k,yMZKY+a3~_R:JXZ!3f\*,ʜp8ܞyլX1V`b}6Σ`2  Gr:LGͳ<^IBhҎ#3 8xEB(sukUV~ ,jjf6"hPRSb\\/<>xMpvAC fgi~8'8<[$$w~GâX{UoN<_x~𾻭Zfa1pgVˈ+a*ʸ9]: 9L_|SO"xk,b*1QK2ɰY<e2x~3UWRuR˲\ y])18],7ʫbr_.ƍ{YjOػgc{}ռ=w-_< ⟍:__tx[Z.X%dZ-W:bs#Z=n".KA%αrʿ,'Jc%*%J8l}\'d؜>Y+U*xF3U2ppNg\f&RО&%P_S=Wu؟t|cCo0//OgbV=^AwSYk cdϊs|'fM:JSx 3bѣ+pW>/ 8JUa*Pbh0g9O UkfR,F_:P~J&o˅8U XAFN_>=?~<e{ wů,<}=K*xMf=.xw dtW/~_`ּE qy[IKSyFGKJɲL *gl-aڍLT0' /{3L_hb8/X0׍LndIb1؜Dh[^>ڳ* \ΤQloς_ =(>|{ON'm~_m]qM{fB|gխgnH/,=Phl4Cc1KdF9uV,xgy&u)P˲ f8\4*c*e?:3ͳ 8wŨש~StiU<.Mac1<*J ?/?c'v3c -7w?cM[~5CjwF5Mj:~!O|.4SxW>*٦wp glc3+q9q {ؼ=:5r-GO*l >*aǎL!0ygN_K';4/U1C'FV|m*rJ_lЯYv|F~0+io@ҼCh_|.>#ZF_i$ӴVfagCkXA} żW(;YU|9ͲLU\=|NOcElIU֩:tRRNtT\Y6iC;2 N6k=,LiGN6KGQ[++Xe+{kxi4w18>_K ѩb+N4СFZjI0NrҌSo5qiaR^zFJZjIB*t9ԩ6F2Ҋmb#Ugv⿄D/^93ik>9.ȏOsiσ?e RK/04#~"Լ//}5O J8.3L'NX  ಼6*G{lqtc?qN9WVf_UGXK<{R>2C7u),F}5g,0 e(~ Joc^~>MgE<3xww4߈|Hk& JoFtxLlqieĘF#Rg<=ce9b ,x[?3 S4q|Ÿ\8h89Х:IaXQ<,O x 8ʄW5*J"ѽs:u ,5K#BHnmn|Cskz.<]."qy- V#-ɲt+qҧ9G,..*g &&|/aɰ&oCX&Ej0rͳll+SHQY>HRgXFx7$\xlLdidF d'k[l7~_?h]WMuQ O[K+τ-g|+me}[~,OsJ9/+!pB.gOf"*1;0˸b9T1jbʲe ]sJ?Yfiopࡊ<8s/FzM, ( ( (>'m~_m]qM{fB|gխgnH/,=Phl4Cc1KdF9uV,xgy&u)P˲ f8\4*c*e?:3ͳ 8wŨש~StiU<.Mac1<*J ?/?c'v3c -7w?cM[~5CjwF5Mj:~!O|.4SxW>*٦wp glc3+q9q {ؼ=:5r-GO*l >*aǎL!0ygN_K';4/U1C'FV|m*rJ_lЯYv|F~0+io@ҼCh_|.>#ZF_i$ӴVfagCkXA} żW(;YU|9ͲLU\=|NOcElIU֩:tRRNtT\Y6iC;2 N6k=,LiGN6 4}I.lk8+hR𿈾 p<5(ω2W09b's+ت3*ڥ~c~ҥ8py^'qYc|9Wƚ3ua, 5KSʭ Ԥ՜P2>mS0/)#|] x>_As5@΍߅~"~#ѯ4MAA3QŦs9c1MJY+3L%l0)N\er⽢[BpTb9%bp9Dp<7|4*f\C\?ԩ*1<Ҿ&Uii֎/.*7 ( ( (??࠿?iۛo?N/kHt(|K(eO9{,izVaw1\j~>fX{V&d3ZN5x7\'❡@P@P@P@P@P@P@( ( ( ( ( ( (?O)gMBml}# ?wWE? ]^υ-ti~?[_5Y|G\ML5k~? jZqǖae}n\^q:sx6x)MU+Uӯ>^%bpC  ;#pm"W:N08xl._}e@__{~ m|_ⷈ9iNմmgo.agh.'^6REz'rl~ ˝w2J\=mt+ B֕~Ѵ M eJ 1 H2ՏU1}}kcxefgWZuZ/odd8r <-O_`i<)ЃrW46rl!P@P@P-eֹ h-f{gz?߇6Zf­J>"|34 g_ujN}z 2jת:ʛt0cTcC Zj?]brj]|dqP F&1)NaA87)ҧV9Ө`)?ۃz_ ߵ_1L9|.h>4[(4C4};Iӭ3M`#_^z8q8EI֯Ru׭RNu*֫RRJ&ܧRr&!N*0aQTbnMrnOm~]Koy_ƻ, = iՠ־(|ZԵtx)w{uh-etšj\wb1Ie6Sう\'Xk<=G㯉"o3~5_ZK gퟠ^꺅4.]*MÖZ^tR/V_ʽj/Rc :bբb֫&Lf&xCLD~Ӓ9(1<=(ӌ!G F:taƝ iRFiӄ!WM|lm=yY| DZ^"׾^şG ^7+[J[J-jV7 Ṯ52[O,cS KqT^%bpC  ;#pm"W:N08xl._}e@__{~ m|_ⷈ9iNմmgo.agh.'^6REz'rl~ ˝w2J\=mt+ B֕~Ѵ M eJ 1 H2ՏU1}}kcxefgWZuZ/odd8r <-O_`i<)ЃrW46rl!P@P@P@?VR~Z쁢xŚmş |~iw_ +H5~A:~o jmP7˖7^b_*mү®]5R*َ& 5jUv1pUvaB\1Ə֣$O 8U3 >JZNC?@T?n :'|-~~džt}3@ltmDۚOҴ}'N6 [X!}zUq'Z"I֯^I9ԫZIJu*TrIRwo81SmFQm6Mɹ>g w-|cs_0xG/'xwVZkR%Z׉hӆ isu݈%dN /s·axV>=8pSuR =UqaH%j֕j[|NPO:1uI0A 0^aP@P@P@Y?k⧀~|R/Ɵ[c𽏍>]/4 ~#O-߅u}jF4k㷚ʜY7 <5ULSףΫ<,q4ѫJ jk)pp3^JgF0^taj:Ju)եZiSLiTr+ (A__^?6.^+ Z ~/ntl-11.4.2/doc/version.cpp.html

/**************************************************************************\

MODULE: version

SUMMARY:

Macros defining the NTL version number.

\**************************************************************************/



#define NTL_VERSION        ... // version number as a string, e.g., "5.2"

#define NTL_MAJOR_VERSION  ... // e.g., 5 in the above example
#define NTL_MINOR_VERSION  ... // e.g., 2        "
#define NTL_REVISION       ... // e.g., 0        "

// The choice as to whether a new version warrants a higher
// Major version number or Minor version number is fairly subjective,
// with no particular rule.

// Revision numbers are only used for small bug fixes that generally
// do not affect the programming interface at all.


ntl-11.5.1/doc/xdouble.cpp.html0000644417616742025610000003307114064716023020040 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/xdouble.cpp.html


/**************************************************************************\

MODULE: xdouble 

SUMMARY:

The class xdouble is used to represent floating point numbers with the
same precision as a 'double', but with extended exponent range
(offering a few more bits than that of a 'long' for the exponent).

The programming interface for xdoubles is almost identical to that of
ordinary doubles.


\**************************************************************************/

#include <NTL/ZZ.h>


class xdouble {

public:

xdouble(); // = 0

xdouble(const xdouble& a);  // copy constructor

explicit xdouble(double a);  // promotion constructor

xdouble& operator=(const xdouble& a);  // assignment operator
xdouble& operator=(double a);

~xdouble();


double mantissa() const;  // read-only access to mantissa
long exponent() const;  // read-only access to exponenent



static void SetOutputPrecision(long p);
// This sets the number of decimal digits to be output.  Default is
// 10.

static long OutputPrecision();
// returns current output precision.

};



/**************************************************************************\

                             Arithmetic Operations

The following are the standard arithmetic operators, whose meaning should 
be clear.

\**************************************************************************/


xdouble operator+(const xdouble& a, const xdouble& b);
xdouble operator-(const xdouble& a, const xdouble& b);
xdouble operator*(const xdouble& a, const xdouble& b);
xdouble operator/(const xdouble& a, const xdouble& b);

// PROMOTIONS: +, -, *, / promote double to xdouble on (a, b).

xdouble operator-(const xdouble& a);

xdouble& operator+=(xdouble& a, const xdouble& b);
xdouble& operator+=(xdouble& a, double b);

xdouble& operator-=(xdouble& a, const xdouble& b);
xdouble& operator-=(xdouble& a, double b);

xdouble& operator*=(xdouble& a, const xdouble& b);
xdouble& operator*=(xdouble& a, double b);

xdouble& operator/=(xdouble& a, const xdouble& b);
xdouble& operator/=(xdouble& a, xdouble b);

xdouble& operator++(xdouble& a); // prefix
void operator++(xdouble& a, int); // postfix

xdouble& operator--(xdouble& a); // prefix
void operator--(xdouble& a, int); // postfix



/**************************************************************************\

                                  Comparison

\**************************************************************************/

long sign(const xdouble& a);
// returns sign (+1, -1, 0) of a

long compare(const xdouble& a, const xdouble& b);
// returns sign of a - b

long operator==(const xdouble& a, const xdouble& b);
long operator!=(const xdouble& a, const xdouble& b);
long operator<=(const xdouble& a, const xdouble& b);
long operator>=(const xdouble& a, const xdouble& b);
long operator <(const xdouble& a, const xdouble& b);
long operator >(const xdouble& a, const xdouble& b);

// PROMOTIONS: compare and operators ==, ..., > promote double to xdouble
// on (a, b).



/**************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ "-" ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 1.5 0.5 .5  5.  -.5 e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine xdouble::SetOutputPrecision(p).  
The default value of p is 10.
The current value of p is returned by a call to xdouble::OutputPrecision().

\**************************************************************************/



ostream& operator<<(ostream& s, const xdouble& a);

istream& operator>>(istream& s, xdouble& x);


/**************************************************************************\

                                  Miscellaneous

\**************************************************************************/



xdouble trunc(const xdouble& a);  // returns integer obtained by truncating
xdouble floor(const xdouble& a);  // returns greatest integer <= a
xdouble ceil(const xdouble& a);   // returns smallest integer >= a
xdouble fabs(const xdouble& a);   // returns |a|
xdouble sqrt(const xdouble& a);   // returns a^{1/2}; error is raised if a < 0

double log(const xdouble& a);  // returns log(a) (note return val is double!)
xdouble xexp(double a);        // returns exp(a) (note argument is double!)
xdouble exp(const double& a);  // equivalent to xexp(to_double(a))


void power(xdouble& z, const xdouble& a, const ZZ& e);
xdouble power(const xdouble& a, const ZZ& e);

void power(xdouble& z, const xdouble& a, long e);
xdouble power(const xdouble& a, long e);
// z = a^e, e may be negative

void power2(xdouble& z, long e);
xdouble power2_xdouble(long e);
// z = 2^e, e may be negative

void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a + b*c, but faster

void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a - b*c, but faster


/**************************************************************************\

Implementation details:

An xdouble is represented as a mantissa/exponent pair (x, e), where x
is a double and e is a long.  The real number represented by (x, e) is
x * NTL_XD_BOUND^e, where

  NTL_XD_BOUND = NTL_XD_HBOUND^2, and
  NTL_XD_HBOUND = 2^{(max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4)}.

Also, the mantissa x satisfies 1/NTL_XD_HBOUND <= |x| <= NTL_XD_HBOUND, except
that the number 0 is always represented as (0, 0).  
Both NTL_XD_BOUND and NTL_XD_HBOUND are macros defined in <NTL/xdouble.h>.

SIZE INVARIANT: |e| < 2^(NTL_BITS_PER_LONG-4).

\**************************************************************************/

ntl-11.5.1/doc/BasicThreadPool.cpp.html0000644417616742025610000007127114064716023021405 0ustar gid-shoupvpug-gid-shoupv ~/ntl-11.4.2/doc/BasicThreadPool.cpp.html


/************************************************************************

MODULE: BasicThreadPool

SUMMARY:

A simple thread pool class BasicThreadPool, as well as some higher-level macros
which facilitite simple parallel for loops.


***************************************************************************/


// ********************** Simple parallel for loops **************************
// 
// We begin with a description of the higher-level macros for writing simple
// parallel for loops.  These facilitaties are activated only when NTL is
// configured with NTL_THREAD_BOOST=on (which implies NTL_THREADS=on).
// However, code that uses these facilties should still compile and run
// correctly even when NTL_THREAD_BOOST=off, or even when NTL_THREADS=off, so
// this is the simplest way to write parallel for loops across a range of
// compile-time and run-time environments.  Note that if NTL_THREADS=on, C++11
// features are reqired, but when NTL_THREADS=off, these features are not
// required, so the code should compile on older C++ compilers.
// 
// Here is a simple recipe for writing parallel for loop.
// 
// At the start of program execution, your program should execute

   SetNumThreads(nt);

// You can choose nt to be any positive integer, but for best results, it
// should correspond to the number of available cores on your machine.
// [NOTE: if NTL_THREAD_BOOST=off, this function is still defined, but does
// nothing.]
// 
// Now consider the following routine:

   void mul(ZZ *x, const ZZ *a, const ZZ *b, long n)
   {
      for (long i = 0; i < n; i++)
         mul(x[i], a[i], b[i]);
   }

// We can parallelize it as follows:

   void mul(ZZ *x, const ZZ *a, const ZZ *b, long n)
   {
      NTL_EXEC_RANGE(n, first, last)

         for (long i = first; i < last; i++)
            mul(x[i], a[i], b[i]);

      NTL_EXEC_RANGE_END
   }

// NTL_EXEC_RANGE and NTL_EXEC_RANGE_END are macros that just "do the right
// thing".  If there are nt threads available, the interval [0..n) will be
// partitioned into (up to)  nt subintervals, and a different thread will be
// used to process each subinterval. You still have to write the for loop
// yourself: the macro just declares and initializes variables "first" and
// "last" (or whatever you want to call them) of type long that represent the
// subinterval [first..last) to be processed by one thread.
// 
// Note that the current thread participates as one of the nt available
// threads, and that the current thread will wait for all other participating threads
// to finish their task before proceeding. The current thread can be identified
// as the one with first == 0.
// 
// Withing the "body" of this construct, you can freely reference any variables
// that are visible at this point.  This is implemented using the C++ lambda
// feature (capturing all variables by reference).
// 
// This construct will still work even if threads are disabled, in which case
// it runs single-threaded with first=0 and last=n.
// 
// Note that the code within the EXEC_RANGE body could call other routines that
// themselves attempt to execute an EXEC_RANGE: if this happens, the latter
// EXEC_RANGE will detect this and run single-threaded.
// 
// You may wish to do other things within the EXEC_RANGE body than just execute
// a loop.  One thing you may want to do is to declare variables.  Another
// thing you may want to do is setup a local context for a ZZ_p modulus (or
// other type of modulus).  Here is an example of doing this:


   void mul(ZZ_p *x, const ZZ_p *a, const ZZ_p *b, long n)
   {
      ZZ_pContext context;
      context.save();

      NTL_EXEC_RANGE(n, first, last)

         context.restore();

         for (long i = first; i < last; i++)
            mul(x[i], a[i], b[i]);

      NTL_EXEC_RANGE_END
   }


// Another useful function is AvailableThreads(), which will return the number
// of available threads.  If threads or thread boosting is not enabled, this
// will return 1.  Even if thread boosting is enabled, this may return 1 if for
// whatever reason, the thread pool is not available for use (for example,
// SetNumThreads was never called, or the thread pool is already active).
// 
// A lower-level set of tools is available, which allow you to simply run a
// specified number of threads.  Assuming nt <= AvailableThreads(), the code

   NTL_EXEC_INDEX(nt, index)

      ... code ...

   NTL_EXEC_INDEX_END

// will execute the body on nt different threads, each with a unique index in
// the range [0..nt).  A variable named "index" (or whatever name you specify)
// of type long will hold the given index.  Just as with EXEC_RANGE, the current
// thread will participate as one of the nt threads, and will always be
// assigned an index of 0.
// 
// This tool is useful if you need to manage memory a bit more carefully.  For
// example, the following code will compute an inner product using all
// available threads:

   ZZ InnerProd(const ZZ *a, const ZZ *b, long n)
   {
      PartitionInfo pinfo(n);

      long cnt = pinfo.NumIntervals();

      Vec<ZZ> acc;
      acc.SetLength(cnt);

      NTL_EXEC_INDEX(cnt, index)

         long first, last;
         pinfo.interval(first, last, index);

         ZZ& sum = acc[index];
         sum = 0;
         for (long i = first; i < last; i++)
            MulAddTo(sum, a[i], b[i]);

      NTL_EXEC_INDEX_END

      ZZ sum;
      sum = 0;
      for (long i = 0; i < cnt; i++)
         sum += acc[i];

      return sum;
   }

// This example also illustrates the class PartitionInfo, which is useful for
// partitioning a large interval into smaller intervals (it is used internally
// by EXEC_RANGE).  The constructor takes a single argument (in this example n)
// and computes a partition of [0..n) into nearly equally sized subintervals.
// The method NumIntervals() returns the number of subintervals, and the method
// interval(first, last, index) sets first and last according to the endpoints
// of the subinterval [first..last) with the given index.
// 
// So in this example, cnt threads will run, each accumulating a sum into a
// corresponding element of the vector acc, and afterwords, these elements are
// summed.
// 
// Note that if threads are not enabled or otherwise unavailable, the above
// code will compile and run correctly (just using one thread).
// 
// Finally, there is a "guarded" version of NTL_EXEC_RANGE called
// NTL_GEXEC_RANGE.  This allows one to dynamically "guard" against parallel
// execution. For example, on very small problems the runtime overhead of a
// parallel for loop may not be worthwhile, or in other situations parallel
// execution could cause incorrect behavior.  See below for details.


// ********************** Other useful patterns *************************
//
// You can use these tools together with some other elements of the
// C++11 standard library to implement some other useful patterns.
//
// ****** Accumulation:
//
// Consider again the example above of computing an inner product.
// This can be implemented more easily as follows:

   ZZ InnerProd(const ZZ *a, const ZZ *b, long n)
   {
      ZZ sum;
      sum = 0;

      std::mutex sum_mutex;

      NTL_EXEC_RANGE(n, first, last)

         ZZ acc;
         acc = 0;

         for (long i = first; i < last; i++)
             MulAddTo(acc, a[i], b[i]);

         std::lock_guard<std::mutex> guard(sum_mutex);
         sum += acc;

      NTL_EXEC_RANGE_END

      return sum;
   }

// There is some extra run-time overead, but in many cases this is negligible.
// Also, unlike the code above for computing an inner product, this code will
// require C++11.

// ****** dynamic scheduling
//
// Suppose you need to perform parallel tasks i = 0..n-1, but the tasks may
// vary greatly in their run time.   A more efficient approach than a simple
// NTL_EXEC_RANGE is as follows:

   long nt = AvailableThreads();
   std::atomic<long> counter(n);

   NTL_EXEC_INDEX(nt, index)

      long i;
      while ((i = --counter) >= 0) {
         // perform task i

         ...
      }

   NTL_EXEC_INDEX_END

// Each time the body of the loop is executed, a different task i = 0..n-1 is
// performed.


// ********************** Simple parallel divide and conquer ************
//
// Some tools are provided for parallelizing simple divide and conquer
// algorithms.  The interface for this set of tools is still experimental
// and subject to change (but hopefully not).
//
// Suppose you have a recursive divide and conquer algorithm:

   void rec_alg(...)
   {
      ...
      // two recursive invocations that can run in parallel
      rec_alg(...call 0...);
      rec_alg(...call 1...);
      ...
   }

// and this algorithm is invoked initially as 

   void alg(...)
   {
      rec_alg(...initial call...);
   }

// Then the following recipe will paralelize it:

   void rec_alg(..., RecursiveThreadPool *pool)
   {
      ...
      NTL_EXEC_DIVIDE(seq, pool, helper, load,
         rec_alg(...call 0..., helper.subpool(0)),
         rec_alg(...call 1..., helper.subpool(1)) )
      ...
   }

   void alg(...)
   {
      rec_alg(...initial call..., NTL_INIT_DIVIDE);
   }

// Here, seq is a boolean "guard" value: if true, the two recursive calls will
// run sequentially, as usual.  Also, load is a floating point number, which
// represents the fraction of threads that should be assigned to call 0.
// If the load should be equally balanced, then load=0.5 is a good choice.
// The name helper is the name of an auxilliary object, which will be in the
// scope of the two recursive calls.  It supplies a method helper.concurrent(),
// which returns true if the two calls are being run concurrently, and false
// otherwise.

// If thread-boosting is not enabled, these macros will revert to the normal
// sequential execution, with no overhead.  If thread-boosting is enabled, then
// the two calls may or may not run concurrently, depending on a number of
// factors.  If they do run concurrently, call 0 will run on the current
// thread, while call 1 will run on another thread; in addition, when the
// current thread finishes execution of call 0, it will wait for the execution
// of call 1 on the other thread to finish before continuing any further.

// As one can see, the use cases here are fairly limited to those in which you
// have a recursive algorithm that calls itself exactly twice.  One example of
// this is QuickSort.  Another example is a recursive FFT.



// ************************** Thread Pools ******************************
// 
// The above facilities are built on top of a more general thread pool class,
// which you may use for your own purposes.
//    
// You create a thread pool by constructing a BasicThreadPool object.  For
// example:

   long nthreads = 4;
   BasicThreadPool pool(nthreads);

// creates a thread pool of 4 threads.  These threads will exist until the
// destructor for pool is called.  
// 
// The simplest way to use a thread pools is as follows.  Suppose you have a
// task that consists of sz subtasks, indexed 0..sz-1.  Then you can write:

   pool.exec_range(sz,
      [&](long first, long last) {
         for (long i = first; i < last; i++) {
            ... code to process subtask i ...
         }
      }
   );

// The second argument to exec_range is a C++11 "lambda".  The "[&]" indicates
// that all local variables in the calling context are captured by reference,
// so the lambda body can reference all visible local variables directly.
// C++11 provides other methods for capturing local variables.  The interval
// [0..sz) is partitioned into subintervals of the form [first..last), which
// are processed by the code in the supplied lambda.
// 
// A lower-level interface is also provided.  One can write:

   pool.exec_index(cnt,
      [&](long index) {
         ... code to process index i ...
      }
   );

// This will activate exactly cnt threads with indices 0..cnt-1, and execute
// the given code on each index.  The parameter cnt must not exceed nthreads,
// otherwise an error is raised.


// ====================================================================
// 
// NOTES:
// 
// When one activates a thread pool with nthreads threads, the *current* thread
// (the one activating the pool) will also participate in the computation.
// This means that the thread pool only contains nthreads-1 other threads.
// 
// If, during an activation, any thread throws an exception, it will be caught
// and rethrown in the activating thread when all the threads complete.  If
// more than one thread throws an exception, the first one that is caught is
// the one that is rethrown.
// 
// Methods are also provided for adding, deleting, and moving threads in and
// among thread pools.
// 
// If NTL_THREADS=off, the corresponding header file may be included, but the
// BasicThreadPool class is not defined.
//
// Unlike most classes in NTL, the BasicThreadPool is not relocatable and hence
// cannot be used in a Vec.  One should first wrap it in a pointer class, such
// as UniquePtr.



// class BasicThreadPool: provided basic functionality for thread pools

class BasicThreadPool {
private:

  BasicThreadPool(const BasicThreadPool&); // disabled
  void operator=(const BasicThreadPool&); // disabled

public:

  explicit
  BasicThreadPool(long nthreads);
  // creates a pool with nthreads threads, including the current thread
  // (so nthreads-1 other threads get created)

  template<class Fct>
  void exec_range(long sz, const Fct& fct);
  // activate by range (see example usage above)

  template<class Fct>
  void exec_index(long cnt, const Fct& fct);
  // activate by index (see example usage above)

  void add(long n = 1);
  // add n threads to the pool

  long NumThreads() const;
  // return number of threads (including current thread)

  void remove(long n = 1);
  // remove n threads from the pool

  void move(BasicThreadPool& other, long n = 1)
  // move n threads from other pool to this pool

  bool active() const;
  // indicates an activation is in process: invoking any of the methods
  // exec_index, exec_range, add, remove, move, or the destructor
  // whie active will raise an error

  template<class Fct>
  static void relaxed_exec_range(BasicThreadPool *pool, long sz, const Fct& fct);
  // similar to pool->exec_range(sz, fct), but will still work even 
  // if !pool or pool->active(), using just the current thread

  template<class Fct>
  static void relaxed_exec_index(BasicThreadPool *pool, long cnt, const Fct& fct);
  // similar to pool->exec_index(cnt, fct), but will still work even 
  // if !pool or pool->active(), provided cnt <= 1, using just the current thread

};




// THREAD BOOSTING FEATURES:

void SetNumThreads(long nt);
// convenience routine to set NTL's thread pool.
// If called more than once, the old thread pool is destroyed and
// replaced by a new one.
// If NTL_THREAD_BOOST=off, then this is still defined, but does nothing.

long AvailableThreads();
// Number of threads currently availble to use in NTL's thread pool.  This is
// always at least 1 (for the current thread).  
// If NTL_THREAD_BOOST=off, then this is still defined, and always returns 1.

BasicThreadPool *GetThreadPool();
void ResetThreadPool(BasicThreadPool *pool = 0);
BasicThreadPool *ReleaseThreadPool();
// Routines to get and set NTL's thread pool.  The interfaces parallel NTL's
// UniquePtr class, and indeed, behind the scenes, NTL's thread pool is stored
// as a UniquePtr<BasicThreadPool>.
// These are only declared when NTL_THREAD_BOOST=on.  


#define NTL_EXEC_RANGE(sz, first, last) ...
#define NTL_EXEC_RANGE_END ...
#define NTL_EXEC_INDEX(cnt, index) ...
#define NTL_EXEC_INDEX_END ...
// convenience macros to implement "parallel for loops" using NTL's thread
// pool.  See examples above for usage.  If NTL_THREAD_BOOST=off, then these
// are still defined, and code will run on a single thread


#define NTL_GEXEC_RANGE(seq, sz, first, last) ...
#define NTL_GEXEC_RANGE_END ...
// "guarded" version of NTL_EXEC_RANGE: if seq evaluates to true, the code runs
// on a single thread.  This is useful in avoiding situations where the
// overhead of a parallel loop is too high.  If seq evaluates to the constant
// true, a good compiler will optimize code to run on a single thread, with no
// overhead.

#define NTL_IMPORT(x) 
// To be used in conjunction with NTL_EXEC_RANGE and friends.  When
// NTL_THREAD_BOOST=on, this will copy the variable named x from the enclosing
// scope to a local copy.  This should only be used for types with cheap
// copies, such as scalars and pointers.  In some situations, this allows the
// compiler to optimize a bit more aggressively.  One or more of these may be
// placed right after an NTL_EXEC_RANGE.
// When NTL_THREAD_BOOST=off, this is still defined, and does nothing.


// class PartitionInfo: A helper class to facilitate partitioning an interval
// into subintervals.  NOTE: this class is available, even when
// NTL_THREAD_BOOST=off.

class PartitionInfo {
public:

   explicit
   PartitionInfo(long sz, long nt = AvailableThreads());
   // partitions [0..sz) into at most nt subintervals.  sz may be 0 or
   // negative, in which case the number of subintervals is 0.

   long NumIntervals() const;
   // return the number of subintervals

   void interval(long& first, long& last, long i) const;
   // [first..last) is the ith interval, where i in [0..NumInvervals()).  No
   // range checking is performed.

};



ntl-11.5.1/doc/zmulrat.jpg0000644417616742025610000141202014064716023017123 0ustar gid-shoupvpug-gid-shoupvJFIFtExifMM*>F(iNߠ8Photoshop 3.08BIM8BIM%ُ B~@ICC_PROFILE0ADBEmntrRGB XYZ  3;acspAPPLnone-ADBE cprt2desc0kwtptbkptrTRCgTRCbTRCrXYZgXYZbXYZtextCopyright 2000 Adobe Systems IncorporateddescAdobe RGB (1998)XYZ QXYZ curv3curv3curv3XYZ OXYZ 4,XYZ &1/ }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzCC ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ()4D> Qc ǟ4xg' h4ݶ/\i'XoC[1h4IH([l jmb1,O=βx5?kS.=qgt})09Ln7p UyV89&ps,aV _ZץZ!WR/mML~|R5k 7D"3KO]񍧇|!9%&om'Gox^SEtmKM}o2ppx"J cG }ԫeܟ,ԣmeXlUJ8}?XZ0 * Y:U+EGV8_k/aG r8j?k>hhvo w3տRhkwxK/,7_RF~S)gaa)U.wc)ǪШO FL|_n?K%w0z %Z8Z.*MX?mB5\Rʤ1h~п[ď׍t߇j~7fEW:Z͖߈Ac{6vcqpUjϞ= T]\N+R4pj*R=jTNQ歈GNXz~_ RHھΝZ6(¥U`0n*p7O S_z_=k}?G៊%C?uϋziuֵ-BJ2|"vφ?|-0]/>׬5o:(.i VP{B.v`p:%/gV"HNFW h&/ ZKVZs[sl0Nؘ9AV_ 8NTax/dSBiC&J j)K1:Fلp05CKbs(ex ԲVW rOΣ(Nq8whf ʰfϰ8Y6Sf*hRL,jס ){jnjgɟO/9>O_x?C"m)i:JD[ҭQ yd֢TrxHk,0rKRo88e¿ g$c#bΥOOeni \0+exxw֩|3giZ*Fyb*ӫV_gt50xysޅk]muKPҵGiR^"^2#TpsgZjrx8׫N{OV3Z' S*9 N/qx Bq|F^RqሩW4>G sB88GԣW/ JXOҟ?_d?ĝ2x^2iM*ᾗD_DԵHg+K[5{+H 7'$ƬTtl.Q;5QӣùLrʷKNa_K/_Ieӡ卣a8JfaXLMF0 (ʅ\5Z]._O S0K ??[~~<~_Kۿ~5xoC㎩? xD>1|$_ş~i_iQްk5y3,ԴPwrb15+QYT?/z0WF8,D*TNJ#Zuc)ѡZn,F3 jX\?֫Q#* NPb MnZЦ|ueO] h4/49dK8FΊ H&U4P帺,\#N EKգRjQUb3# VաV8\0S<6&PUWb)N*|^J/ׅL67CRQR>L)d_tu;%Eaxk]WYŎqKiVe/xMet76Fˤ蚗pXN8*Th壄*)GkUẖyfXѭЙ~]XM\E,/TW[UW88 hʾ3JK%1Y6@slFja# :gO/?ًR7/iA*V46 ]Yq';NO>p̨aR.c$lO9 F.XW˹+0s~ӝ X%OC#O|1q1}r,/~GZzp ?=$xxHIp2s çdܓ޸)%_-c~o7wd]q2M8< >C`Wi~#~5~ 4_hooO8<>SG jSZd66r-xNo!sx/9a=óϛT84W VIWRT*Pp4+1T%C1|a IN.:8B Xn u??9 N~k}w{=SmniWuiW:8H,O#,A͋*8hŒ(g=J(4cR>ɧNT]/JʓtAKyq?d_u٫ ⭾ ƅȲ |m8RUIׯW+Y\Nú V2l5< <gm}G;?| +?O^!@_F/4~Ro/ ?Yh ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ([gqb#8*q/1^xφ ʩ.&8J7ȳ\| ,=Vb;s\q xWG 9Eq;*,,39hW^Ο eyLL#Ke8VUeKj+G =9P~?>;xIZ|'~#o<k_׉'TO_|S/Ŗm]^j"ѽlG\%*4C2O3\LE,+/TzU0at|*1v_q.)>9,e,gets,.L.,E,.1Zp9&u(bBtNКe !`zdpyz#M6WjB3g.^2WN]={Xߵer8~}8_mio^"ӤU<3Sil/"̻г!QNwVia|3Ȟ}PKcrx\ *8Is]jrW`Is+⽷|CCyuo2|:>3>"qx/Se^3/֨իR#NaW'_V\ѕ?d? 1K?gk_ANJEཿnOS!0|+n/47wG|'ox]P)wӣU)g2{9`F<\!3C4)_sIa+ETb+S͸{gO6qNiBN NT͟c1y_%f8Zxc#/L>aqX )G8hBVKMN9G<_~ߴsBӯ'xm-*×*GyIi5qA"!ٱv3>2VZx<^Y:u%V88tT*URSIG Q ㇩RCFqJ^4ʋR]9Rn(7i~??n'ߴ5xwY|UAR=7ᇌ>#_x_Im~4+ ռ#Xk7M]+Ei_wŘ*wIW*ҧZrNT=icpMCOWbZ~W<> ˨YE IҎqt7bp 8(Yc(6\V7*Uq[O e"a|~jx_̚Cĭ>3|@\m彛O{yqJ~ jZM{uiYy}q3 0x<>{X NQt]< pգ8У:y] Q4:y`q3ΰ97Rm֧~%0DU%fR! #_ u)?e?sm?¿>3V2}?3/QЮF[x[V6r5W8C)s>3*X%OK/|3TpL<⾦6J#9^s r\<jOJp9- EFuTg l-FrXaŵ >^Y??4{/j^;5 zV߳GB_4ךhԼ3Fwt#DR>mxr 5WQļQ<5w!˸[1-eUsCR{I&#múqP]>ᬝSaewƸ~/ʲn#oiQF/%a.R08:( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LMd~пH_%zOKRk~.hv!~)CibLլS9hWw[k~qkpUL.+bkP˸_!G:NAR5pSխRHgI%;O_7+d~XLžiCÜ1 0K1gN+ g5V.*bŏ&['V_bo^!|)㟉?6|(5*Oh~ >0Mz޿>0.Czu/uúzXLesphClFUSΰaC*Ӧfkgʳ17+qY#3S\o֯WzxʵX犭͋0ON-)a<E_o_>?<#oO {V#~]_T OL5g;}BEꖋ;$4kg4!Fr̳0!SSyn#a3g5I/4e/ ]Wef'=>Qs2o׊5izTچ2? >#|Af>^۷w<i<׾*nZ~~?k6ZRKs,pjKNP&Kx>$ౙvAY.' R3~X8Bo0 Q ߍ12 q)b5Q2jxOc.(`h&c>JN4x>-W>"?'yv'|=/?g&~K> xzLJ"m_i8;)ct֥Ģx^x|!{ƚC0\꘷ j˨^ip"<-QNrq[9ˈqNa8flYO6̳.!xm_O^'.Ee<9v:𘼋jƮ X9qXΛk X # Yϸxz\F#E^ BWJ5G V#BVU\~şG'vSK/o"=2#"ȁ.gF_xqfՖĘvVg}SKj;ܓ?Rw!6*KXӜ:OjsAJQ{|'ּW/KҦ4ٗQ ͕5'tݼp7IIylYbY Z3I^)oVuK3#FlL V<.`QVsQ/jZމ}Ne ACiwarjVsoĜ3.8%C5oë'Uu&y4RgRwSg_ج6iVgج8x']`)UbdR)__o>'|Sewuw5_[x {+(Qu:=/h={H톡}:S.",U\1_?O ve, 5,u<6)IƖŪUG/.癟K.91"jd_Zj|;<; xkYqZ|:8CM<f <1|1>BsasN:ѥ uaC%ӥJY %1f2z~60ۜϲt}K=8 ju08NX'_,=ԡW (煿z?i?_XW·vK].]o]ݯlgK 6CZu瞗 ; xy̪ccKKZUs7œOU*r:G1w|MLX9kLe<)`#`7UqQCg CBt50m{HΌpaVtg ?-j$#ρogW}CĺOԸҵsAkzբ1ZOr6M{~ľg9Zx9AT\"£B*c B>IW' $\aodQT%R8M,3`%"Xq 2P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( /_o ⟆?/z?GMy5[& : ) u|EX @ D/W+y<I`pnsg̱,3P(^_'Gٹ<B3b DSd'74'['GCÅ~+m~:[~ο~*xꑥՆ#2|5_0`ᱸlfqMJ 9wJ3rX.f0XlLW+Kx: Y#'::Tq=_cٯ?]6<73W[jEi67onu_xOjK>^NcS)C3v?JX|Ca'Vw4ir|VU^r Bu֫(PNZrO ^Ua)bK L4|sc <m^x3:5Ɓ;oxenFOkѣAxg:>j;zXpYTq# Zl*3J)pzRSV>"QqSNӥU{,^Q JT+Ԍ*$ћj3hBp_ e|PBмe|EL=?fwsƟL~w)F5I5 xL H SX׆-<65_F)Nw`.s 'G/sj9>nkaPJS}sLǒ%5(C e2 3n?B7[WԌsBHBXOk&'gjCů?Sy;?{/64yş _|5|>ׅ|I>a kZ_УG#FX0x\OlO^*5 X4+N/V%Cc12Q#b%ɉslvuժ`T)aUQqZWom2Wcއ->ï.~ I-ÿ \>/4;Tj[S*rq f Tey*XBUV|ljS0M<7 V=%05xxLU\r<Ά GrQ V7\K=Wĺ11u5G:~˾'|*mCȷ^t-&x;XmΫ6m^Xg5kje"s:ysKHa$֮9><O؊Ԏ_ᰘ(Nze ԫRnSdkʲ><=,UYa!Ɇo1sZuqrQ:ܥ.o_?/ k{iC[oO OxAhM*K|OOKaWt]E&R;U'iJNNjrObaeRt}5\># ?kB">Ft+rNaS^ʽ5z)ք'[ kIύ_ُ^zdkkS%o.5'Ǎ?uZrat$6ڣV*ҫGJ ?VxᰰAB!󦩪nyҔy%YUg SjJTJTj=J2KJQtS÷P/[;7_19y>xKFþ(ZާotDz=OV--ާ{u{4imV̡J1 8*qOQ<:էJx5BTi8FYMdpt0xPxE|}iЅ/`f18{G.x급#::n_P ?`|֮j/? 9h?ZMށX ]ɬOD4]_N?c?iBMU%e8`^&z1EFxUՖ& *4+ =X}^?d/ۿdžgڛo ?coi~.L :׆<;qauŞգ4mu -bGeWW^8իNUUQ)IΥoi>iNJJS^[d~?*OfYv(`P52?/:qohcr#t)]s?̏QF33bAV!9?G-|}>~AAO k>" Z,w77-5ķֳ,]9"VaZ]j &N\˰4i~iԩYN9r`8\`4bNsfxFcRSqX Stc Q#K}n~&~u$LA o}*-R~hT"'5:ro/aեI:B׫YVT0ySUJL<.uXSXz*i`՚X .çM1]Sx걫:׈NЧV0jTSg؛zßٷ.Ou[COdcEMӢl,<ebiYxy!QmnSe8Sז%{jqu+#X/SxjS:SVXiӫN &+OӣJiprЭM B:PZ]*u:xl4)}I\g@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( (;O--3ƺ6uKZ86Ú,[maaYڵWM:Zj~KeYYiFexZ$|,ϨHs)F0ҡ^qJZi`*xT8 3JH"1qp)VaJp*sӔ/i(( ( (?&xGHs=tPJ( ((gH`)RAI`ऑ`%x]W]bV]uWkQ&% ( ( ( ( ( ((g?6h|ȒǾSz]K")"26X)>JQ}d٩&kFkqqiE=dMhOt,hP@P@P@P@P@P@P@P@P@P@P@x|oŏi5g|d7{]j௉׼)ek BNկںixVJ[-z {H5++Ԟ 'G0WFf}F8CJ1> U}=(Ԅ*ԌN3W+ҥWe9L=jTG69SiJץ:SS {MAA@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( ( ( (?&_h__~@~Q]jo=>1~пgÿٗG?/y3M<2k{|&7_J}ya5|aaV JiB?NjRڊʾqÙkPX+k*k 'NWD-1_O?jO2_~xNΑ|1ky[x]#Zp'm-_q>eLf#,οrhfᇞubien{L7q VxK.>[6s*:Z?)7q]Z5~6 ˊG,WbUK0Y=*WU^[Ɗ=xP@P@P@P@P@~rm,ҿßoS??=DCOW4|K_x+8KR'ki>}Z Ğ>;[_bL&c= դ{WB*\<;Jlk*hIO3ִ1j<.K4%\/1XN'REPuο{/+w^5?&{;ۣ ;ʈ; G,:p<˞jV%)%%)[zs e|"qbqN[J䃯ѭU|u''.s)q3ҿ >+ûCAqx!{_| YZG5Gkbyc ~W90G1I 7'֣GxhԫBx9bg*0j)*_YB2yq,-a*e5\*,u q(FgWR.f[*f9Fyʬ$cx5uN+-xҥBeӝ:WҋRsP@P@P@P@P@P?O j/ڻZψЮ||XSzuƛܧS⏊n|-g隤_IWPܶ?$WVbqPYNIFqs)z3 $sU VY{<*S 6# G s\R%GɢflP@P@P@P@P@RmE9I)I$KVjx*)@wكޗ<>3x3W%|I𯌯5iYO|6KS5m/ Ԯ|GO8N&t0)ʳyBf+D*s__ҕlFWCbR?3XF3Jٶ6ԔN,K%:6#- Ϋ.s,(IQˡW,WIP@P@P@P@P@PX^>4'?WO|h??o?:¿'v? g?^;q|G{J[R'1oJxZ>[SYx168\l&pzkf_iJز\&(C43Zk0,.O5F7:,GBpXۉ(U8Jy~Kp,Nw+P̣10yfSa1S+nR߰{,ؼMMǕ,N3w M<4-xT՛' j~eН|=hN"Cӭ RF<%:u)֣5jө SNc8T1g eN:?`:~5|egG=ݗ+eA_xZuxC+b?֡ >? GC*8Ƽa<xN80U'TjಬJx=eV#[ՄY~4䴳L& G,n'+ᬾ:8\fcsLTur+3QayM)gOMg/^9e5{#XCoi:eiV6~X6vv[CaKBT(b8'qT|_s**J*՝ZҝIT.,fq/Xڸz/Ͳ, RG )ѯO/ǶZ4 S*N?f@( ( ( ( (?o:ľ*~izot;ZXW;L۬4ɮy67 ugw' m;'+paʟeR1x74e;)hϳFcT%N7is|u*oFhTR*qV:q~| '|K׆6xpujR i#{>%r\FWR ~ĩ9%漳2m/vVJ^-/iEp7NZTzN?aEߧ8j W(6A]?lo* bo.Q6QK}'B9IszAvg⿍>.AJ3׋Tn(5p>deb ]_UO*tj-R9Yc REb|B}rfC>)#x8z(b*u~g?l_~1ؿ: | !xW~G/<{o_&x泤;} M֍Úͅs_CsN%qWeK*ƅ\"q8;Se{}OJ_,!O^3-ީ\^Cadv?27Ga+S~gGaSl_)F* :ʤ|/ȳfWmrF+c#VUWN,BJ y%MC#awf"d|]}hۗbw]_ž|M(?OxIu Jhzb^Ϭkqls}:Fx\{f7,qKS\Ѝ,6. ~bpTx[Nq^7S(V#UA5SVU(&QRM\,/\G`m9ʖ:ڲsqVkvP@P@P@P@P@~KD-|AOL_ٛZ~8|Mⷅ!eOآ?~-Ym7whe񞵮)msaSx3a]iPa QSOUqu:v.bqDbqX+՜nU@P@P@P@P@P@p/R/+]_x)f?:=Z'$ xIu+ k:Wǿ? A;cakS$q|[YLhe1]c :yS)̰Y_3SwRjMf̳~fᾫQ˰Tkqi,ʞaq1Wa'Ko s G_Mgheyߥ|6 j׼yŞ1/8xڮgL+wiy*:^(} vg Ӊ8wf,eZ\?֍JY&*pyts 'Fz( ( ( ( ( (*O? fMR|?V|7?:_(H?L~2!5w"5֯8?.4¶9Z-q>NY^+xU>SI͇~/F9ii</B%5ʽ\^3 q$w/l# dxlvl~jsl:ʸO:(c*b>Ëi; ,_^MPb>jfWَ;7xlEh`0q,409uZ^E~ok$ 9Ab#w>|:cD?|X7'O|sX|]x<3=RגU?_R،kX8g_WV''0UeZRƺr  ni v/ \˳<.]S-V6kFY~=afY_Vì6cZy\B ( ( (( ( ( ( (?&_h__~@x/W_u ㇈< ow[MlijefڜZEŚ_"NztOZ<=\D!׫T*UITotJR&WnISTNJ'N*QRo5*FԜRJMAFٛoWI=~Ͽ~umcgOuk!v,_hh/ŵ/.`b)W3x:V V&՚b)abkѠ߱VzgR PIC8\4qUqP7B24iUl6& WjPV*У9tjb3ʽW/ǿ% \~ܿR_*싪ZXȐ~?G7̯}5$v-wa*1@s*>1T1/3GXᱳage:qfTz9#<۩9ۈkqlyO˄puqngn&⷏14d^eЧ8'xh?|L 7ltxsVZ_w]M_L,nF)Okok &uqp :#˲5(ңmR4Rha驸A~8zXomNi{2tb1*}^4WWUѧwiרO׋n*޺qЗ.n[Pde>|u(ax֞>񎹧'\]iڬLRG|~aCi )CV'8d!c*t3iA{Jס8LE^W*<b2v/.xWS//4^; ö(u[OzZ#UH4L{|)J+JOWמKC0La2BHWbf֧c)aUx_*uGye\S_1<%bgb -/mT<+NtrA:~U5f;2RJKTiOUw€ ( ( ( ( (?_8s 2|)ٟV3t=dB<eg/W]ϡsׄ)/Ǜ/{ikAtyC0͡siejJEVX|8*ӌcpʫ`x ./ 2F e|LhUxNa byLs3Q㱘[R\L=2\}fRV3q_1EyBHLpo/#41[oo<8 ߶8@~*TgO O^QrTORJRܛmˣT088cjapQlThb*S:pU*O#h1J% ( ( ( ( ( !|em?k/?y'^&|, W-!'OtkrhoZ0 k]Ԧ\)*ᲚymĹXfì~gMƊO.ܱbkO' P91?+Q40UsZ]<QqgFNaj"i_['Gŝw ]XS6wƶ@8Y7n|/ÅXj<^ ǶvwVԾ98Ra ᰹*T:x\&'?Ibs,V2S#&~Ε|078YrԖ_J%WbE^~,T#RucciS[jeƛw ]h%ƚ=φ+'3XMKijjz]ˮڴZuKxm4s(Wq˱4b2R`kƽHIN)Q*rJRl2ʘzn_W cTf aB'^+KMƴG>x)tvP@P@P@P@P@0 캰)&!_o.t7Z?>?u֋? U|Ym}oW- "S&ռo•hFo.%WB/r4(丬; ֎I 3,uslV +XB6=5Rl!Ïpøb!9K1x[UW52O*Ŭѡ_25߶¿_K#Ƕ߲vuώuMa> w/~!ټ/ͨī{ ЩWr"˾K)|tN415=0򥊎 hIRĘ K 0LlG`*#>"B| 9&Lj_ `(Մ<2ex|fɰ&&kl4`ap+TP@P@P@P@P@~.i?n+_y_~8xG?Oㅇ¿jď >?ÞtSUռWg{> M7L7ڽՎgs{*fYVaUb88zU* ]UV{8IaѥR5*b*PZ樤eZ'dl&Xڶ*ʫq8w/U:uh(i)׫R Tua|[~۟23>*A~vK}Y-QDžn#t]F++xk=Rr[|K0AOYG NiƎvS=!|: kZ^xgG쵹WE%_T;+ټ+a_Ck\Fnc2|GĬ :*xNBwUex< XnUcbo'!t_&p009/PPYS^^W밣R9W~߳?M/OOg44Yu=^K95MRu˫2oϳEg9i5,f*L.|9v}6_ ?f q|vETr.<NxKJ4+bqF*0g TS {uyP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ wźMփE6|/4kIUmʷZv͝«ʳB04))%8%%ԭ%wfݨQ,ڼ^vꞏTd/~hh\5ԺG5_LֹC{Ph| ]eRN IƜe)8ӋB/H&ڍf嚄#)1GRj)JrNܷ~gaPPP@P@P@P@P@P@dP]'zn֚zZ 3P݊A$l@%r!Q(RTZd\i8vi %:s9Ҕ$$dӳqzNJm|#= {ѼS]H <#cZʭIIT)QڊvWQJ^1:pB2){svwk]uAa@P@P@( ( (Mdmw޿p/ 1Nǟ {~ԼAx#|W᫽Wš_iމu{\^%ѵmWm6c(ԧ౴' <̲U)*|n_ FӯP +Ҕէ%(IŦ]jsⱘ*f_j' 8xKzη?|0_xwƗmᯍvèr CٽYUNyX*Ӓe)QC{Y)פGzPSC8_ G4Tü'^m$6l!f*3^TJqXlN+ S0 y&yy^iOi,M!i%Gfy%v,&#}F0s1"c)F1IF1I%I+>R)Ns397)JM)IIlC U=};ߍ~(_Ƌַ|}|1[,#S|E8|YqcfҼ;h ?g8JLp>2 1pG4Ua*=|'3|fV4J=># 0\٬.ΞOIU1<(f즥<"[cFuOK@bٿU%O |;jVk|}w |`9>1OY ƫ!y]=}f9& ua!ro:o%PrXb*Xz.rWtzR' %KK +泩W8̫bs|Z15kשxkVK ZeVYqT( (ɯ#??)W@P3?|e|SŚwtSs_]Ac54 xVFuwm#]hIRӯ)) u 3夕,?NuM{ZqB2J4's?Fu#JT} L犂u=LF]N(9U:\Tb4?Q<ws _^%tH2\iVO<IewU}mJ3J *Y2:qaN&aݷh(|OV|*ZrV]VJ0ԧ9ɫ')I;-C?ƚ&E#YCԦTNMF; "D/7ׅYWx4mUnl2*5!(sC++U }'[R`10()ʚQԥ^x/g*Iscƛqu12>S^7~ox_º=E-7N{v if$hycXx<=LEU'j)B :jTiѡF-N"F>hJNI8l=LUzxz\%niB8RjݥF8ʭz)RME?__jKkúfWGf OwZTho3ZxXe%P>,-ЬKeE{_O>mqjnluPúu=Gԭ}JXUMQQ招JrU%QNJ==GMrʣel|j񽿋o|Ct]OHtS. b!ug`X?Lno) ۫渹5_*`:3u*֔eYӎ %JPQ"$iS/9ɧ)I,_O(ҧy~jfINu*T);ښJ)~W8O2x/ |4+_:ƕYf7j:I-͞t^%2Y:J|I*|8n,\$){'Eg[Ҍ%/lMMNP^UkI78Rs#90?ό @_Ϣu//>XGi'rx\,+;JѵKje԰iί*jJC]R(<ε%Z/iVpl3nW T,F*HR:P ӯVqR]F-5NerR_K/:z>gx:埃 BFS]%um7H4붶Ky"ypYvG+t0=kքgjsai)JU1QԅjT*at8F"1|=VWMn//J5yo=f\[Yh=KNstג^!Li+$3f4x|=ホף*k^IbgɆ#j ,o[ M8a\+$aRN9RKTKr^G':V*E (I${/ʉ+JK_ER);SoqM,}:}ߊ߶ώ~/Z20>k3].>*ִ]i,> CMմv.[+՛g2|=rSax]'_^7^&3\<8a\LuHa/zSVYg8(轒RMNXRcBT+{WVS%Z(Û&oP'ᯍW[}?EҬ&oon~rYlbxg$# 긺ӝi*`|T)՜TigJTibR)*qRT\hFJZ'[~ <8ӴO/=aDV H[UoN.KIgzVW^|a^GhsJ/Q^z* o XfSgIP.IЅ +L01Se=8oRJXDK8XxbjUtoVr,<=>:x7 \~:;㏈~Ŧg}gY~GĚG-wFvL.7XZCufu}mqa/zYLXl""r:]B·4y7Z*R:ŬZxLZZ ,&+Bxu,xZV&hV [%js}g↋O>+x~&w3_IVy˛BZ=訓\w]̨Oi#½ ~xRVVPrQV>i{9V֣Ur#wb%BUN rq8Z0JRQ*j{*%R$7M3( N|{]}~7ן?m#|M⯄~/W^SKWgxƚ> 4 OL7cq%K)|=ŧSruуچ3+֧;ھ#,jRc*.iV'G0tG ^Wq*|>t*:ʗ<'!T3 1'2I'*g8RT:q9i RoK(nIɨm$[ߗ~Xoۻ Y|d~5wAK/toGTKxczwiiZPiŲm]k rOL^%Q#/eJ5iiμ+PjFT!a5G4t#FT2N/R/'%Z*<= Rԅ(Kg5 Щw߳G/z?;F߉| xĻ'M5?|>#d mck$zޛ'Q_ke`b#Fcce̩QTPr Xd R8tO3QQZ8N# m)e IT|+`'Yף![))JUӞԜ)gjX.-S2fr\h+Z xo6)k[Ě CpE /q9lG_,T{zѯ_R8aײ(:pêVVUeW Z'+:t֫Z1u3zQuB OFx !:'K%7ϊx?|_y?icio^ävZuky_Kii  ߐUS*UeF']_QgٽN-*4iSPtJi =ŕsU 6iZoZ:|'-G֐76Wzv4uƟfa¸W\N-`|@l&k% ~ n`Ή'H䷵"DP}V/'9b^7q .ehʾ+QifqӫRYө*B?dkvi,) iNQYb6*ԣ+V4c*OAx/x :m:xG~,O,E=XvxmݥKBI (s`~ڼ7<իΏ;'ٷkGù#UYO)9:8by功/2I4d(!@ZC/ٖ-cy"v^EɴJѣMYƯ7u=.#JN48FSP[~R珴t]EOs)8FR\I~:j|=cAo¯Wm+K|/U|KSHҼK F^*aZV'4J-0oҝ, aGUWu+*kTڍ<:Jc9TVL$*u%\ܮ8xΚ(9k)SNؼYS^ucR,iR-RѕY%ʍj#!\Su ='Ou O, N#KhjGv6ڞ-|q[mX[Ivꗆ ~HeGX^oN ^Xsӆ/ NUULt(F8aӲż>1Px8Rx63O0UM *J:Q\Ҍ<ץ璍n6ҿਿlY[_ ~!ED%5m;@ZҴ4^5Ѵ+x4ďF"`,IlӸn\,m %brlU5Z?X*Y]zӜ1q\U*RAMBrLޖJx<e5^WUS/vtЫW 0L2MOiU7JԦxO?g RV/2_zGe/aB U_|C.}iaao[_D(,=&7Uy4o-mLTx_i['a`RtV\OmZ QhUl>Kp^TfRq:Ÿs{Z##@gnk>[~ݯya?*GO |B ͥ|o!4}&yi y3@Ѵ$yjV7[D*G Zu>'Z>\c2-js=&J(<ҢFhtx{18CNtp}w<B*M`)|?i+SsZgZg:NyKɈdȁ >;  *x<.#8Ť =֔Sz&M}:0jV IUb(᩹ETR4ғQRQ{߳'{_/|C}#ú7~ͧ4xRHI6zޏHڵ΍e5ŝu| l&Vⱘ,kK:m.1J8V*:*ա;T]<pᏯ*)Q_ԇT:ӕN,z/_?eO+|&ΕåGiZΥacieCq }Xk/lRN/:YJjt 0R8bdtJΥ^[P8*T%ˇ)匣W-V_*8o1#T)S09౔Fu*RS)q=  (h[[Q''ÚWg\'ķƫ;T-+#?Ocoi[gİ-:6i uOܳ;pKdoRcR ա Ui<R*RRUWJ\89'2xT~:XhU |&O&cp* ¥dS>( ZEŨwWzF-yg[Eg%3]|p]|W̪ _]qW<]uRY޾!1)R+׊?/aqQ*3y>, p8LJU0iV9\18,>SEUՕj:~_i/'?~|V7x|U|@7;o 0)-5?^!}GDkh43UaMb)eS7p|MLofѭ:^ʧFxXWF%2Sphc| Lpk*_`\Ig.`s|=:X":lnj8Z7Zp<"Ph(}ad #N?h u2hZ%& 5yw&ɵkkh^gyl=B19=,ن3j|,}eҧwY\:,E8RCR\|KƸ\A8(]QJq|0S.z> x1Vzv c^@x_t3O797\4_|-CEW ih0 K<9`n\mxr7z'M&Qtןjaayu[y\lnE'?iFCغӄdEZeN5%9L~ϛj<-\J"q(RJ2ZiQ~0V/x5!,rx{2~_ W4}0Aayo3Cqh6$xo5-JKhS%W{NW˃ fWNw|GY7)RǚT]hҭ:Nq&?'`ΎX(U\|<9OUg%ju.xO>* x3=k>'֧qA=@PK00YQ՝J, afIE>J)hZKԧ4'KAb)TJeZޜR帉(S!JU)B^YХTr1=#Uֲ,( go|HO>x&]Zկl=[]./2+;s%<7yo ~?.qk`L:z!=Cž1 4YеCfi" vDA }aɚ5^EYJRW Ez')JRVIԜ&)9;6g}L6K9^pN҄iх:TӥNJ#N#ta#튃7 )[Uoxƾ#dž5gxZi kZf"xkN_ yZu>Saf'jwC 0ܶQbUa^t>xkp lζoX+?_r̶U|n2_z8x^12p}A;>2ռEeԞF×<˧ijZ<3˨:5%~]}_Lp9cWٕxc$qMgZ"t9)Wf]\EZui`q9|fAgYÏٽ<&yЫ_ap5y8L&c({/cj*8+ OŕS3G/~-{Cj5ogG ZӦKm>Khnl%MIR)=(2nGŘ^hK ^9e~gSө(էEzgFtGu=ʭ/xw,|758"˰(:~6"t1t*O 8ROriF\/S->sWO_+<3q⯈i7pãX/joɦkRO}`ZhJʰ82AMTu^V8BJ^4 QrʜY|_a^URNx=:No 0Ξ5c Bx5iΚ+EC:  (̞:º -<'}ㅊ:xVY帺izίoiKsg]4o (dtΧ}<9J2<5'+)I'sJ^wQCt K*StSgMq%Cq?5xw]K υ:-u涚IE$5K1?-J(gm7NҢmryR*jZu,-sʣu0ԠJ>3EIV;U#B49u[ [•<R)N0CF4՜T?iQMSFԽH_? w?)4?NXRG<H~>=?To0=xvK-/};x;M2=2[k;x:~J"X,>.# '[Ab)"AaUeV+ESs73JY ]l-Tj8+<6<jXZQ 2jpN,>nQfߎ1KgTu|L:mu>KKgNm6w@,"luK++-:K0ҖE]*yjW9)խ8,MX*8lWF QgyI^N2TV ,=:L*T)/g s '(d+Ti2Wg~Yx[Mk[ NBĚ.kZ㼽-WjǼ{h:1iNepӆW ZXlV"u NuZ).JSPXN14hཻAG|1?aҭ,|(u_ءb5{YZ1ZCWvCյ]+S泲G<.;-:9•K#NzxJRMaxhWß < eYu,Zŏ x_Q?b{žUZ~wqcx}s̳ QO f' Ֆ&ƞ' OץN~8њ?6>Qbi$hbm<:O )+ΝL,R4' u0'eZbY؛B_OjQg{XP]!JN~O 366/t{ $Lw Nk;,8I吡Eˉ|Bpu01U(a8' 9`1LF깆a(b'QUJ^JTr>uGfs֌aÄ8*FQY]|3ϥ)NYJsm'edGM|A@P@_F/4~Ro/ ?Yh+e[w^Fe7<4{CO>5}Vu#xJ|E"LYwR:T\S}qSm).j ^,S['kLAqVp(* =[V?M?3,FMђ(1dCUfQ'pJ2*B+=z^vr3%*kf!vgt>~Zw> 5k >ԴiψvN˭? KK,YVÑSxΟ>J Nղ*rxh̥C|"3Ed6cΛq TM8tlTѪet8Tcox/5? d滿+#<ˇ~Q)KU!guh  (ȏ'_|a!só?VyY"~$~HXb6NY_8|Ec?>2=; = _wş [g XBnu/ivNvjͻmuQZR]>Llmߎ>23huc{J~ԊQׯr~B}>J1Xԍ)WU*J0~? |c&xK%ΡaŸxZ?/4xFka'SUյXhvj^ۻtaXŁ NQ*cP&1U15b( % <%Viь#j_<8r{9Φ/6GIζ&լ8< R?c0ݙMFier}\iuLPI5cei6b@fN/dV]T#^QF#ɻ7ު_P@okex Ήȗ?蟮1EL9_C?! 1q5 )S:&5Ԏ*1R5wJ2U)ErzsMM852kGW{?G`_eAܟ^KH_ú{N瓄}cJ1„J9~DhEdˌUYAjUDE;.|qbX_HeIrL W`v<6v??+Wv?fvɥ-V#R:K~3LL(kOUg;N֗/?bx}gُ-O .| IoStwmN|!߲'N'*4X^]R|n6]`Yrѩ̥G <=S;'5hѪa!ҧVX|_A`:RNpZΔGV!2')|u\|Eէ?x_E_}_6uGNzy䲱":6wrgexA`Tœ:8YjR|*R{:XB搎fqfUgZ?\l&5pZ1uGlr?w' 4aX( (C ; oڷGĿKg¿8xyUCVF~ւ +)|?xkMklI x U:ο ǿ~|6Dw~o7L[O]ޤ4eҭ-PԴۭKXZ!]2}Vh^L&#+2,'WcF*UcU4ו^z'KZcgY5sSF.aEU]J~닉`YOB^Ϥt^EO9]EV ^QP@~HS3?Uy_-^CWUH~ւ9/M}o_ϦB:},h߿[_#?Cأ2:ǥ(<*UeS0x\oW{}sMW\@t e68]<^&?"[OxF]6_416&K4Ҧ6[5[-D?՜S^pduPNy|o?oATNHʥu e({?mi+6q39gJiΞ V?\L 4*TFcpiy;:֝ɼ%xSմ q>2ԣͭɠuoyDg5ˊUJ3N|n䭄Ȱ Xo_幂RCtTT}>Jx\*F EsTY&1᪯rt֩NSVNqvR@PkiSחȗ7^aM?/-D5p7K>'M֋ p't0Ka,~2')N6cN'Qs>Č?p/,T||*Zu}15jeU+`j2uo?(1kNeO tӥrd<% ts xl:{pxoY3 N[yVL0zjա_+U)1J&cr%U`iU~ٿB x_~*t Im]7z(<@-1Lju#:Ƈo _[xM*G0ʱxZR<}zxӞ|年صb)+qwG˳qX:[b!VabsZXz̢ļdˇkRHbhXJG*%RʫU*5%Zxƽ,]:ҴRҩ E*^:1'fnkBn# IB(=*kUЧxPT冩BJ;J (ȏ(gc}nde#/0vp?Xxw7-?l"[D & )=B7yyO,FVTӯ'0+R&ާYI{Wz2MsU? *1zFk)Pw?!$cwI/*6>W/{kGT1,,0 OJ4Æ _3"ir=81SލggzWភgnS~~OW\6*jm+ʝ(nu%:*; (>$g9Wq]dQe?5?aԚGLk?9FԢI^^a?!$ce/UA]쇛x¯&o+gѨ+:aj[o"onakY J_}^x4aC(YIVc)s9ӧ,6"< b^e;Ѿ|_|GOx`?]CNtxRZ[M2Cww<1$_QIT,sc?&wWbp|k½ޞ"X,%hb0԰ㄧ>g$1+W* <{J UL=qغQxZq؊^½JOCo~1~^ W?&]_>o>9мkm?ښDZTx'\7CdMӢ[K}.=6W3yE^U8܃3Ƽ0\qu#+:Xu~&LDx7?'p9 p+2n 1x얾Z٦U1,v3/T㖼)玒dWtx7~:KZYfO*i4vDrc.2FNQ)Znx,f+RPyN9ʍISs AXy&kC=ɲ ]̨ӪV p].U[Go Lt|2b(5-yWe*ƻ1p).e?l[O ^ƚ.+KtZ|Ej,S<iK_ WZUZ=ZFߙfυsupqjή; F[W5`c /,4XjTG7mϐg;V, f/>*h֍J g#G'`6&HPӧ/ko=xGG#2J1 ,2n`?'h䰞W(ע*2%)u.?VZP@s&I >_'?J cWabPqϟJ0Z6y/Z~eG3` <. ?ct]RSOe[_YΠAHG }z50aG (ՍJnӴӳGqisᱸj<ڷ= E(֥+=W59{t-GHP@!a)ֿۢ:Mgo|4/㙲JarC]?y1۳~5vTiu%.\=xa=Qۖr5ĺk^nz8K,F{|iVWpIs_^ ɟοK|5ƾ6zb̗TroJ5wj_WwK^ОA 3▻[LVOzeȆWhzPZ^{Jl-B^aᅯ^':ؚ4%JN(֎U:j|M[ 7ЕYrRX:|R;/˰^PR8(B-9(_e/i\σ~~z~ xPse}Gn^//m,ҼXu4S[hg69<.;+S0S.PR6;-0*|UOTb]jN80ؼ>' *xn1 WJ%*5Fua U*գM? \]#ė"wx[V!FÂB9]+VhQaoeT2 12aЖ(*m=WԡuЩuR燣uܩ^IFMͬK ( (?( ( ('^t z׉|A[i:tG][=3HlԵ 3jE1~*٦6'j.͗`2<% Sh&C1a3*s't818Ruysf؜}O2a|E XE)B<~2~^~?|5n_؟E;#~^[J_m/+x#P&Iuizn'6O/.$zssw+W`36rP$)HեS6YZ'NZJQ2S9{JWS4jWOz'ѩOC3RpZpWpUVOWZҋ!9Q82>k,Srn/FJq:XjjQ)5 )¬"(> |je7.(WS%SFvsWomK^"AӴد'ya _6q/ij]ﲰ* |ԫTe%3#uRQooF. "^ q*tK zm.ibM]…Z\ ߳溄fz͟u+ 4>$ |Uhz4M''OA ;:_?<l5صKVGmnՒbkeuҩ._?V$we(ЛU<5^oi*1#.itJ Uaѧ(?iJ7jEX8s9Zܭ~2_-|cs.ZY|^o=QZGk}k&͓RJiqun]U8TZcliMteV)*cVtFtgP ө Rsm^ە>XVԒtܜc'(T8A)5|h%Q?xCNe#J>+ӆYo﮴4;Q߅`Ң^\mJr*lV1R*],jPLM7BmׇT"m{W<<`ԉ9 XL*z֜qRL_xR Qա%xoE|Wp_k?_%mi H5)U҆6w~~𷉴/mltoAռ,)~֣i:̣kG2l;԰qq_]b08Ҩݱ3Vdb:2&@P|ZgL5+Yu[X4߈z6m˥[AkwKok%ci N%HTNSVpz:r'PS۩R9Յ*ҍ) \Uԥ­*N3i{HҊIҦV#/g*bK ?|Έ=g<.֨> xC(GGnCkuԯnib[ oRT2 $JkVM LSUiF6:ӨƓ' (_kwTMUJ0ůa5*)”(ί5XՋi*r3 k߳m4}oL*>&}rD{{{Oi.2rgUl&"8bk9*J) OOF"ֱk (qz(KYԶ&T)oxZ'ظRZ}cj*F_Axo X|) ~9X米Lt(.5 Ti7%춰aku}& >*thJ&UB)J=^WP iNs.ܗ7hUBlDף9쪺QZrsۧzMz_ >"xP1~0|2Mn3E$+IOSvg +75I:?FSUMiǮjksZlNt05c<ʴg[:6p% GF4{*VVU^\+kEO R}8cSԪՔܔq\9N~VѳJhV>{io?!o~( _>(Z]Z4WM\0!a^]`hdTNoW'4*8L,] aiׯyd+J(ʊhʧ&/`3}*G,(8c[֕|Bqq\naRU:8*xW`hP@x_t|Si~~$|IjU<mo_8l ZCӵF: K RN[ yfOXu'p|DO5j1n;߻UMTPѶ"T+Rߋ#jb\gX O1:rLB:,*ZR1sl=_߃_W?|2Լ iDXWı|S/|aJ s~~i%n5{fԬ &屶S晜rJ&I쎂І*uq=G#(uHs{ h P8?_3v+vskctׯX*]a]RgtaEU敪9R%: Ux֥gc\jVs\0Yf\CO2T25TyuHJ\[{)aJ~Uį_>%CZv|$}67LZ {>熼!xzho;a$bәѢO+?e&SiƄ10nU7Rk)Q:P(ͱY*©f8¨f8P2O9'ԩ9p)Τ"N syIt8i(+&Uݮ%ս~~k/_xo/)|a9H~-Bu <-~ '{a}Oy#1Zt9m*' aMkT厢Z^J3凵ru2}9Bu:!I?8᝹U]"䚼b)?]@I^5uc.ggᏊ R`"of [cYWkvls_ F3XN JUaF> N4(tjҬ%X2pn# 5S K)W:RqNJeF=JR SR挑 #UCo5Þ&߃M {qٽ*yI^<<c1rVUiҩP5ћRU!ԣxK (?'|]V3m>v)'ŸLIֵ./ IqwnfO B|V ̱!hUT*1ORRb(F'Z'ˉ(|_f1xՎ%˫XOԍaeU<Le\>Jxg2o_ ~%||/K|]t!׾ Y7gOѢ6rl=Coh/>[ eYOS 1/ZfYoO_)aBnʧ:߅Uq=b2\!.'N66X?cE*I{z*Gq}URpO/;Yை>+_?aZ?46c{=?i"?,GߧhZgAU{V"_iSêxŚ*љ~(&sG{5fe$ct1ʱ9V;*ONlW37L LMLgQ2OC`O ̳:9kFT0m䓩Px8,"TСj0>ʶX?m|IُQߌExAquo6[\g]v|qYM{l&Ocjf{[?*S`)MҖcT3 MWBu G3e844oBmԉyj_GGJtk{J$F_W1N/;qwnc4W 沧,! :Zu)xb>1AaԡV<XVYq:p\ש*].~:uhQ L 7CJ3:JfmIUZw?5;x'}s^+SRx XXgַ-%Τgou+l%\Z*q2X|,}.B-,<ܫxhZ42/nJç[-?UI:zT}r{S9i4~п?h96|I|~?L` ]S?ᯆ0K^h#l.W5iZ3ex:u!/J2G(`8elgN37'>LNcGL=G*Xjrr>8(2c(ԔjBN,O 9x{}gmk!Sk:`Þ]jM^{mk+O"jRt)RԜ*bqxh{|& 'R\ҝzO NU',Š9q5rXaRthF\3Q=\@Pߵa!_56:|$S?]i6zַ\I=N#ݬIYHTo1Y>}9#8- p8%S5421)SPLE(|K><"~&>c|K!`q^)yU|U_`JhKǛa^X}aN3}5ϪqW>L;1_a2\ _4bBJZ?UTMla9_C𞙿7?$Om-e^QFrG*˰9m*V`p԰$JM'vޮS ( oQo@C6hzNKxsJ5J=:[4[Vծ#F7O*dgR;INrHW|r-N2MNq!RjZo)=tZ~%'|A=Kic7 k7|񍾿qj6 \\iMYĖ%8o2y}J|Kug4(Q/({5^zpSyuhEGIsRu#MJ~sr4W48Ѫ]:nn1sR喴ԽgWy _|8v+oxY_Z kIt:n;k%Le-X4s_[f45,ړ)z )N ^Zx5cVL>Ы:t}LE&!_ ^Ub0惝JN`^zN._ ~-?d? 8>i^M/t:g+xwW/Cax]χu-;S}CXs%GOk5m+f6 NgPc2XG,&4c*¤*ia*YtgUԥ:rTg ]}]QNiխ StyүK H' S|S3~7jޘakwam.uo }BpNʜجU\6eW MwZ:0sάV_eXyL K*˧V*lMTt*bjRUk% p*ҝuMTO^P@fGSWsįE?@a3twv6ϋ4].{ڭO[r\=ռoT, k⪬$cR:TquW㉲SӄMΧ\g1ʰ謷9̷̱ 5,+jЭKJx|#Y)?N.4z$>>|"}+<9b5|nGu?x4EOR67kL,`%9fl%`QCN[˲TT3U}b*3oFj{ Їy&Ekq qUq-x^aө[J/IARskA>|'j^3{frIU^4*k}֫tU3,昞&rf&:<˖tjˡ?oROU;N87,*e#Gq]<)d#̲;̽&9c+ЩIT(<F,+Tg9|0Gu|/<}ρu];Q㏆^nNw[~_Zx~Vh9u焵]xX',{PмS :w(,D<3k-ͅ"}6KܡNKx CNy,uGQGIg=.[tl^]S'Q*qտexJW<}jk8PEbqjPPxxwNN7X3a*,Cz(Jmm/M,Jm-v+3eQ ,NI9}'<^'oiWSZ%!|g/xCߊ=SD--֝k^cm@Co}2l2' C b+9^4ba"JJu'֫VIMԡ:&:ufOx4iU\$x_R鿳} ~ Q~/៌|F~%i7WCui:=/%֬f5&H/+YZ/8<5LQM,N KQVTE5MT:q9xihfSG.^3_8*2bV*sWß?MKx{Gmm|M Ec'/lvm7YYsc#[)ጻ%֎/R'S:hpaץK #,n2ҫN~ˡ9b 8n|>'xcǿlĸFgF5OϪV2x4oek>Ʊm}h,M -Ӟ+N-J,&sb[ȰAWW\|*u(咎6aWq8ʙĭ)P\FP?1jG ú2nZX?`ً\~jGY_+|K+ FHӼ5%hs=ܶm 2LXL .r9eMN׵P(ҫ^+Z4C u9'Z* >#^9.~k4}KR;,p `l9<368.q63S CC =cp >27 ռ5mV^KD&I.?5඿o?g' '׼z}4R'-GJѯƞ3uK/𞫤ju쥾Ix1nFYFY&.LW0oF}V'eՓ+b+.L>Ţ*6U:s:=|mnONyaq#U)b!(f!߲O*Xuhɫ,xA~[kIy~iӴc]47P[- .XO5Ms'c(W2x 1hcO C)ʋRlC<j\L*r}S̩c=Wc>JoK1hF/Zg DIRT%O9C3 B>=@|YCSg xV^+fB>)OmA'>m:fmgZ1[Z[Ck'^#aRn*j'^G @=jGܽ7' Pj5F ?]lx._r>"4S'_;cGUu*J5/غ# YGxi,KKOE>G+Z3C0ħN#/:ST1OO m#'􏈚NGÍ{pn Ѵ*u 7)n/O Gq3r\|f^+/Y,&N.J)ŨO _l?i&oxlô,ͱaW3ĸeO3(ju% ."xu Wya(VE"Eox-y ZY%1֬?~Y[ue4lipT0;aR8,1Uֵ޾"Ifx`u㰘 ZgQVgV5Ur*Qg!N uFX>WVo¼,p8^Y .^4{xx+w|a|+|fy5-?W5]Ro] h:gGqsۋ 8*o1rb㥙cU4b0^+FwN0N2:ZY\&g^/(gԳJxcEbO sXgJiJg yO~>-k0xQeod-)Σsw X5,T2GfJ_^7 fxj~ icihS0Ux|.gp*ԩV*')R6#_ 8K2e1\FT)Ʀ/[N!F"Z4SN ΑA@PuJ^Lz|OHޝӾYi%8uO]iF1uyhrC7 Y WX,aWsxv]5%׊?4 oRm㱾ҚUuCMӴ|pα Uy"ѩN9N  ^(RUZY1'V6S GeVT3%ejRǾUq8y\|=FQ:Qt>#ZX~x߳˪zM_o3{&KOWzׇn"𿉚Q6Im o5N\a\1hVj+cp~*T0)Bnh4p8ʝ|<04bp*au+Ruj 8B*'5i7Ᾱ^$6g<1Ϯiw"In.j[@A95 vw2'iWrpt[014m !Jln#FYBc:\jQBhS?mV_zv%V89ɸѡ ԥ hQ`_3~: >#xnit!#@M>-KXE<}<%:K*IW\=,T~hԄhFU49R99S ʤ'\rR3ue  [/BGn橥j7EKi7<1Kio1mU.{(R*38v#/RjY՜9ΥIRs roaYՆ Mr̳1qZT p\F1"!vE|u _Q|BGPG*SVV %+2iQ*Rt-QBPO S|*M:jto 9>^S_L?h~0}W[@R.'_IG?ƹ :e9Yg{?b#Gx'JS$c(҄JB3MӥkU#N4?թbiFQpRzVJWVz?0=_~ |Ls?YS|An%-M9: +TdUd|juJ|5i(*0^4/e O*nSV< );vm;;^ϣۛO~xeƟƳ]t<?i |7_[4][ּK:1zj:EsgY\3"Ue:*Ժa6XUF*1S֌$ƧRE>n J9PB2XuQJZF>4)Q(JP4Vq<0G$J*GH^I YYWO B&(TVoӥRrc˧NujB8T8ӄVSRӯSYj_~=|h_h^<񯂼1MBug{CVVei~yu,Gkh C,6Obk ZskO OKӧ8|]:SQjc+f^YT)|bMЍIѨK?`uNRf^2G_|a[VO^s%Mƥn[OU]R-36e[2!Ʀg㽕zYv!ҝFLU: T52h/eU(7 {\S[xjٙ%Vj0تKǟ?j'I|AoO6K|':mo&vynd[|X :tqY`NrFn9NS(rs <`88:c+і64kL*ER8foN,5FS)}1~~">$|pwlK1o=H=žU{˹/&{mth$UC z*Z#jMZJУ :siƞ49JkU*5(aA´NjW<5jyaN1N2"k( _dңU> v|-|EMIk>% <1=1^@ylh֨,8l'+TXjZ?Xx=":զJZIJYN攛gc3,e.4ks<]1e\Ӎ (Nᇤ_ҵ*hJ"֚֏˯)'| ~ïxSHOcč?:'o=VOisZLXݶ& b'jq40WձxUh`2\lLc*r}QUƝ,5UW* E90Y0xv]NLP! ,4Ek+FU/>ubښͣ~4O*xVUe5Z1V'Z0VLD u֧Jq|(>Ew\,oajZt2v$P,h!yΕuEʝ\2./ 0*fX:-(!I;i ȟ"/brb.@ ՝h՝QQ*u#JXҫ(5NQSRtΗ/4orF%R8.tԹजir9FR-gkߵ t?'L=,xsB/+6k׈&77u}T[Aious 5T;a:U#r? TNYb/̝gF3h\EX:vRaYJuRѝ4(r*V`1EmbamwGRve=qUV(y#rQxU#Wĺqu=9pߨ 5F Sa)[p=j 7ni+;.cH^#Dƺ14?|?#^ g[x7Ww$Cwޛo ӴNFRܰ+eYW U؜sBToJsOS:RVQWO fcSCuZXYA)WQ7ZJ*\)ʥɇ )x_DOo?~-V&u ڶamgxL&KImcTʈ˃e9&&,*[R[P.gR#Ubҋ0u¶jJX8~ȟ?h S-b|hON b^5|7I-"&?skuRUUK}Ly5x;ڴgV# *2J؜SgV<^& .&PW)T2UکG挰Rg_Jn:1",> l.28lEz߶UtP@)~~{ gB/#G_xW4-SQ[/ƾ  qn2Emk %8Bn,!+F01o8s5fV;Snxf"*r7*R)YR~?L+h?j~)v<MG Ωk^A$o|OZ\xR'omtY.lqqq԰qhfp<=<11԰lB^,|t0sjx4qʂ&# |¸:uxL?gXc}p ]aoU͎R3KQ]Yו)x7\<sR-h>xO|?iؼ^?K\]]}=6+QcTҖ'4ҫ:d9iTW~^"/iۃĿxkPcmoZ۫{(|ao5 +ϷUӎ=lZ_%C$x&; y#3;˩c(3hC# ԧFN+XJ-xb0f.yuLF5"8z楈]Zҧ9:6"4llh( [Wе84MnL8kN=Ɛv Aav]K!{Mln9"jJJQBP89Gݹ~˥RjRNUƤ%Vj{UyӍ^JSrOnI[iǏ_$к=?ķ~%d <MkGo?Ꚍz Ru(M qYmY|AaOp'՛',V n*Ay҂9RsFg>w !UqΝ85Ʌ̸rQu&+J^Iӌ$J꪿TGĿ ~6ͥ>!mr,R[xJ$GV{mh %|@_wGo;i> |/-+Nn/%7WWzaծ (by"u KA珰JoeGSJ68xG8c1xʮ#O Sxӥ^Jx8ʵ4kZB~0ߴ'SRFYB%5 F5Ŀk/#K8{*ק*pz:շU+b%_Rr *tEK~o:A}i?zYji~5xn t+o ^_yWsF!5dCaGC3 e :ZX橘ƫhES){)ʞ-{_sfy+*$*#G[qUiW5Ԥ!NuՍu 3$Aºukĺ㏉> /VwU-ޣ\]]Hff^GXVę8])vaAZ1cxnaÙ+0bؚGsc1U[IU:)MZRa]GMSc!^QwT>7g\մO xOYMwRlWῊɼXdY8{,J`,V7 9&mV.. 4>8*cZF?\y\iV>|<1'Eo3f #77OO~-x qv9E:vi:^O}Iq_xvmhT!f1=G ~YZJp<",U)GRypU0xܿSK(nUs<|g^cƆ&8ЯbX4'j᱔9{qX^$|/iAēsAi˧-ơp;;FinyR9إsWK'dR|H'i{CD[k[n(f408ITdyZ4:4-JcʥHTaU158x0} P1x=f<@o7L&uf-Ld0:2~€ ( S淧S_o4ۻ}w"xD剖R$ң!iX_(CzV5gTg(U/Nε5(Qƥ߲^JӔ#+ԃJEOߕ9FJWT8qxsG/??KjP_?5hv_#cqxo⭋Yiޕľn5]jX^2Zy]`-*uMUiv$)м-P>hrNyQ*ei~>K:4:/:VQ^MSR{:uN?/:o~:Fi~|[}oVҮI-!U[}:T9q`uӌjVQ<59˖uJ2kbjҤ䗺}lu`baSөR*w5Ek(ТZkOvU%|OhxŞ0Rω_<ῄOt JӬnt[}{-Foޫbr0Xjukx ^g/l’ty)ҧ}[QR̓2X^2qS`(:j$*taׯ*!2FօiCOO?LkǺ~'[xėfCxn!E>C5xM=͓I?[5N>8G6G1q Jtia؊Q|a3 RpWt0T15}'^^6 0YMZ𙏖]a&r`3pN4,MXՖ24/>:j^ )|"rxL;I;O\cb\Ỵ lM Uic=^PG)JsӥGr8 %ST:0Ĭ=Ju {JPN69VNqVE:KG:(Kֿ >7j6??1|n#~&|z'٭g]?u/ ֗O%V#њ KeqN;46& VenK<^+^7bf|C*؜Uj՗dU)rvRmg5gS-sg~_|M>>㛝?Wנ{PYeM𦇫D_nS%E_kax(`(֭˱U's<b08ip42=yUe :K8C*b1<>˪xMHc1s,n_◳2 'b1D+⣌'F)i\ow OO'ď/牼w7>5RS4[[ӭDծt:duxfGŒTةƼS zSeم Qjbj|v*xjT>o>#]|3)a2#湆a̕|&/0T,¾*tԣflN#?a03S7u>5Yf5ς~.ψ:u<kv)o@h.x[/lWnZV0eC 9 K[ 9ut2=J8S`v*iG3Nƶ"x.e<,3T -ʲ" u O3f,>+224uxjZ/_fx")~$x~9^.!ӯ7?wo#x-1.]7_n,/m{!ԭ5%ghb*G|A(թWK RUs|$*RhJ5q)baRjLY~K0,#`hq#Qy.3 b㾷*"e^e:Pa?]o?YZ;]y;]]y;vP@Kv]_L,|˨GVeeJK?A=w6[GΤjIES897>jjI 9FqToVHҔFMէ*tEF5=YҜhJYSnx~L*2>FQ฽,!9O25.;HN_@G8U\#SaVZRKxD#NiQg7FUspE{gJ}(|*,dOsFRZUjJq Q%H/m>fo ݞ<OW#CҥrЦa&xL#._oV sWb`UN2R:hFpӨ~8T)0|N#rUЫ*NiUxzU.sr5gf٦!|R_ߋ71ӼQ|R߅-~j7 ?;hцe%ƇZ=ݠZZS a,",j𘊹W_c6{:CSTN8KKaq(ⰴrt13ՅJҝZjUVU]dʦ"X؎/GߵU[_%Ailg% 4*Yj bqRR,Mx~&40%:8Z8 ^+pl6/S K3UO ޤj,2̨St%3Sg(iKgO`kk?4~.? ]^O!}j?m$rqd!m;zOۘ-C :8`qWW´\,\p(SNSJGt,j֯QL pt'F<>S])^jհ'DI{?ciT,eLW9h/_=eE;~"j#[ZNn4}oJTUi6ڌĮ.K46<1u%JcҧSa9kWC hR*P[,K]WQ5*|VҔJ*U0%VsTqXzU%Rt"sP@P@( ( $|%l/).2/g|,&h~*xs6hׅ~o>Yxنg_-<3qZ\QF *ק,G<]*rtUD|0~1xbfORhVO!aqhK ZiVTqYn*.l#q#x֟f>&TZ7-ǿ xEޏ1uo$k>ėSK\\^jk)4̱֒AY;p#RU9ԣ%VstR$W2ܷ)?̣,KNQz2VIDTg*GAtZR]?a|O% Ɨy]~6 iM jGxw/t? ^ߌjyf3QhPohQ81֥RYᣒSxc2^8n/zqVIGjR[:1n`SO(LrKRL >(fB`0PS'/տR KɿόIo|mu cq|>^ֵ? <%ŴimxxX|me\p1cfCN_ k`eÙ}\}.\ƭl :^uglLMJ4lwakxX:Ce=،%,asn].UՔ2a+aTxf3f_’|D?: s⛻e[謴_C$x/?mQSxk.qD<8u+b88+ڹ̖1[ueԣ,SGVS>7URR VX~Yes0[եakYj`Z4NxLmi\GZ$B (?&_h__~@W3mg?o[T9eyh%?Dȇ|7k*G9TLD7Du[|&"MubK~'.dPǸ2l%Fؐa_7%/հFo~Vc?q[OK4[_[|F~G޺p{ӳסw}|iǍ4>]xNӦ麯gxL]Ey6o|/]%G˒UTjө/cNUpQ9c:nHI9pӊg \ҌVAԔ:j5I)A8JIFJ(A|7n< ډ 7|K[[k*4d[N]lm&dҝn0Kbx9pJ4kk,N ua֣j Kkdߟyt+W R XZ"C8ӯK .<.1ጭ_?_4_22__ŪjwC *%dj5?G\AY'Yvv2$ŷz|Yto}r~ol1^;~/V v7bvwDutP@Y6_'wLKn s_TT?GS1J# Hcq=;IJƪTZgIѨO+)YKzM78%2KU[jVGnWoǕe{t鍏r<;6.֗q]aTq^|1: ƃcT_:iݷu 'voVcFxˉcYV0(2^"UtINb!,'89i>cp::w_?e=rnYi;Er+ 3rluy-{3^=MoQhk^9BM>ZSĞ?sK}SC5Ki?XO |2+ɫiV̱ᥜ_\0m?prī9ץqJrTХK2uMʽ[*SN{B1өSK ӭkN% ٝdc18|:tF{iJޱxvߎ9U3V0K4{o8,IVYY}c*Ƭ$)9ЩP(Zs+Ԧ(؍e 85qY85VCT6ƭ v!BLpúx}NxÞ >* ?^ּ0[n1 xTףh>Ư5Eؿ.wNEӭ͕1kKVlT, , O1>0l6_*U*V0x,ƂRo㱟Y5(`88yTEjRRR ogqe| TAٮ>$xbQ.Q3xJL )۞NY9[T' OJFCI;$\ьe/iTjGZu3oa*MWՃI8i]G (?$?੿t*.x~*QTW ZycXYJj3$UJ%L2Udcdx4:9jvHN긼IFNʖ *_€ ( ןw^觯/<.obQ*a(_Z? ?j?Oɲ|%El5 .%Je.c9kνZ?'k{B!/߇+?i ]xjZݚῇ&W[_kTڅi+!:Rivs?®8̨ugC* MFw(ʎPNt0,L}~jjaksρn;jW$^# .3'IU2,EWCKP?3ÿFZx_|30L.oy>;Or~kIܗ YׯRN `҂Pm,>aB$ڥF)S?@r&E>r%%qj"D*֩:^^]XP@lomÿUc̿YeN?]f駺Gz( WnŘ'[[rHkάSҥ*o,4kR*<:ۖ\N2}\M\iU? -1*T%-p/_!$cwI/*6>W/{kGT1?8':.|?8dz'plVym||RQr '⇭8W]>t>~> 䖟>#Zۻxj6[:W{co=oËSmϡiUѭnuiqgϱPUϚ\CbxY' n(fTgGJJuqU|>43z&[R`Tc7 6q-E[)UU|(1Hl?g O|EF4 4=SVyw.z5 52Xa uu{Ϥx[Teu2&%َ2c)cgOC.8F~amS$2(Kh\O4cbaq \|mz|Gߴ.4X[LJ)x_Zk Zַ'Φ˫j=˨6uf<;ps,<EetgV-`㈡NO rX<< 8+b2لqxFiGa2\WpU0SF*.֟-6^=_eiep>cCi3( Gz6+k 8n5XqUFY5sT{#K7rx~naiWCi?c9ʟ:/2m4޸h( ?%<]kuE%Fod>/$Qe\??G_:߿E :D|,3Hml~̛L[Ȣ†]6K <ʏWieN W7+;1ʛh8OU/6bɍ _}}/.>;Y5𾻒;kKM)溽 [&KPƱH#UYjӣZ!J.-VJ!N<u'989IjR|ގ{Nux%8JI tԜz!Rdy;%v{w_ K(i_P6_7ƯxoE'<]}OֺI$2z^,ʰhΎj:W ^!X5a)bkѣ)c:uMTX\ AťuS]w*1(RjZ>$]Ϋ^"׼6jH,gZخ&ia]Vg12eqXXXUqTc(2EhueK ;̨G.)p}|(s?g[ ian^GCVIJ$傧]S%_(( _J&>|LgS#\/I~{ƼcoJ.O_Jf?QbY5~fZi 4Z֡mƑܐא Y"NxPP<(~4qKUjP¶.P*u5e PzjӲ |nr#*^tZsT?tMZ%ݩ~)OֳN};\i?Kw o[Kcvv_hVx~đҬou_7:X)q&wʃStxg.j{8hTbZԲF/^KV9v`dR~;¹%yC2ls7x\vgNL= {0\N:3 5X#<l797O?|7Eo6xuh qa>7 6i5w x@olxL?a M7'V8|G]vOiVSTT1aa15n-0V[13gugj֞,~6x 7OVgZo<)Yܺ IKЦm5!i3,7ze$KXofXyqbYxUT? JwT![Z RFxJ2~31<%tr̫aRw0X2Jn J1YScO,5k-SJԴJNto,onIo,K{[$I 'I#bp9J87BiQQiW[h~FE*uiסVJƥ*ө8IkEӺn-ԚP@0߳'Omß R\ +HGbAηCN" $ld/߅jZd~lme:| mciZeVv60ƣ 8kWj%V4ܛQVUbbJ)EhJiS擜sRTs9Jsr5P (M[_P}rOSp8<Ź?_a?ǟ/o=ÿ3.]|Ø̳Hrٜ\)HPSW-QЭc 8L?I9?k? ?c? ſ{W/u;GN׼equAɢ[8m5+Byk? %u9V G 0ԱyQ:v+r)aS;ҞX#WqX/wĉ` &Sq#dH8lUĘcRu1Tha lX\}$ca_?7 wğ~X1]-x3q|0NS<3;6W[}kA1yVXk&becHN%,vTRWaqLcb,̸o:噮'8G$RQխX<8kR1ԱQPJ+-U8YՔ3JhamXӼC:rN]YJ++{i23q~b1Z䯆WZOʝH]>Yūg~_f g8<6; Rl]b(N9T4( k_m&Mppn~|d~ւ>~œ8kN_n~"xDݢI:~a,^%`[S}d%gr2OP)F%SrT}ehGG?Cg_%c_ORfKl7oO٫ǿVwK7eVI"5=r\[YkV:}ݪJK/ap1\ FPO0T%6*0TؕBRspUa^aVtZt8xVjNL~$TF;`N]XҭRtc92Q~*|U>!_ [S׃?O|=oz5+O} numKyN>a溚F]L֖*`jxLF]`i׫V8zJS9o8lR#x'+Xֲ0$\ixZٰ}ͯ$)Hxe4r+y]:;&`kV<j0<J.3Gɹs›c-sIUؙVb)̥WXj“Ӓjwo7#>(( ( ( ( ( ●5{m ox\!/_׵;ddDKdguP^voR4 i0>Œe:҄K )raiU+WN8sN._`ϋ̱l.uUB5j*SNm/v7zXwx i|mdO'Ÿ Y$:S[ x[މOA43 \[TxF}Glz?ʝGfnj1|T<6|,n R fG*fPY/b1xY`2LƦ)C8pQ1x nWpR1eis/oZxF0Ƕ7gk;ii]&1aV]y|2s^U:|8x,OV"J-Y'YUWVkQ EIc!KN#% "q/G0ϱμYƖ" -aK Gdrx߯㱿5A@P@_F/4~Ro/ ?Yhʏ(j//7ѨGm>%j?>vhM,ͧxfP밵Ә=]tmR")̊TWW^V#RIVKemW1IArЩJ3spiץN_Y 犕8ѓ`3 ɩiʅ\+TnUU0_g|cִ _X |ou~:G{mnlnKԮⶎY8- /Octԯ 44q3Zc5B^ΚoUUE5 .׵ ү,]HQN'(9yom#Kr<2|7J?3?< iɁyM),}Dq_-{[⽓tz8_a/5VXPv5;;i *~/o cό?h' <'5m_G%/kkƗJvվWɱQROα: *V`cqR|3̨N*rT}O 8sqQ xWO& 8h/xAҵ bI5%{dÒxld\^Tg搆 NKQbbNUkBx}]B|ژs %]RUj30s(CO5)ѥ<.)/p;K_b6x:G>5&ԴW5Wpi]jZ]槨۽>YS9v7+NKGj5+18)BX=:P'i]9U/V76΄x2a0*TcCC Rhڔ^/4Xzw<\W|<aWW^w1ݜ_xtn_/تa@P|W]S-g>><]\iYO&6cFҥKKkmA.!k8F2}LwaAEu=)FrW-җa0昈ԧհzꪸl2+.hʪ]1&x/>/--MɧoKoBZx!C32'ΜF>gOC v*x.8/o"xJTT27e\WSWbq*J_2H,l8jү_Qץ UaSS9_?K1N࿴lB㨋7\'O< S[/YocܾΰV֚xJ5}7?f%]3ڂ6ET2V87i߱pOg͉xxηbh~5u[AL-ziM~f]O|A k^89d|cI$)i'l@6vQEn9r.Y2.J4Œ:u15-LMwJ3VqiѦ#AG ' V;Wfxvxj՞#|GZ5Y05Mի^?b?>#  x_eJҭ~,2LWڏn}5l#z;鷗io{ Hk)} P86jG4.KT:~֮>870kT'R7^|RG0\%q.S\YqnmxEӯ昌/.T ĺRbp v.)@g|~.h/xS&_Cմѡg[OCyk޵:|XU㵊P%30,q],_W̞i:ty^]¥\FgMѩ[Bqʦ?YO-ue;C [3JcGS*fT6ySУN3*ғxfԞcK//?;1ky}2PbWFuZ8ex/-tp4kwNj00X"k ``p.,F.t}!P*bs#^(է !^.eUj¾6S̫֔عԧJNT0էFZ|-*թBR}P@aP[LY/كQѼQ|YkcH|Oh6^$дtŪ[_tK-e*᳌;%e9Rueb=Rcp披)ivUXL ѧG')(ԴKE'V)ixk~*xTo?u_rcmx<].[O^zc/[ ȸR4} ӝjt%NpNcFTN^&JZq*qxyʢgI}9hΚF4w!j0F#R~)|{?G?H$4B5pg:q~׷ >+.hQ^£_,3E`=5:ly}GLy?k0To^t~ -KC^|ns|'?o?a*CּaWsISDgKVNt$jֱKE,)Ee,N0t*QsSG5% t]b*F2 \œqΨN2 YqE*jjZUkUJ1H,DF*(2&ᖑF?~J񕦇,j,\:5a]ǩk!7[hӀju .{\&E(Ƥԭ[77*u%?*t~')V)NXueNsM*TV3NV*Oց_ğ 9G_wⷊ#?#ޡ ⼺}C(dqu|\$Mp7:*:u89:OPO Nz77R2Np|Μz^z:SSVh{DJRn~l~_oƿ>#GW$h)~k| Ěz]βEtB?FN\(-}S*ڕ ^5}l%rpr.R>#Lmvqq cqtq1ۂb*ù:UKN70?qkP (ɾ-xW2}[F{qu OYr5ZS}BĖf5!bK=EZiQ{-Բ-vgis9‡,e(f..cjƷևX^You:=aeNMNχj-?b\|Km:n4e#Huk>+=V+-~EVa3\*b2>21iGj8q3Q*ӝx祶 Ta1pAa5' ڔAץ=IRSQR({55 |c\ߴmzgŸIfGP:&-wx?'uOu,7"VnnK_Vڶ 'l.KTC1XʱmNq9ӯOE xWKr.T)7jࣁ6t#:^(M:1QJs Ta?I|6W>NkҼ5ZyǧiqY[5T]ʐ\yWRMq)i$vqxq5#J\%T(СMF wj(BmE3<68Z)Ԓj&ׯQB1ZsW198&z7 (?lW>7d+M3=|tWL6vvv"m&Nn[M,<._ԥdj.7ԃgZP_꺋B*ٔ)Wɳnxy!TtphԟYNTN~74]B?O֯kz?;C4GQn8ZP۽AoެpB]y:х*T9aMѩU<*Nq)R9rSugI ){H29UU)EiR s#dw >v t)_ c::x?.|\,r< ٮ\N'QYS {v~Z~G~,~'~ |G>w^?Y_6Z8lB: |^axZت+3΅<6eUa[OJmJ*irtlүN>2|?l4O|-g{ھOEDu?ͦO{achtٖwIcs{!{" 5e5%Fg>UӔ kPUF e*j&RY;5Nt `#]EWl\bgJr)|6:Q8NlBd5js6T7kW_~#~Z/~+. ͇XoEԥ|6'[DD}IƧ{G3YŧC4)-֜;>UdX pX70UOTєWbV1*c)SVS_p68^sO14mCM.t],xw~ ۼ7:i M5#Wz-s|;+2\3,dp8:t!xL&"ZrfaNqUMUjW8VUVpY|WP*ǛS#'7ė^TթBǏ~^xxw|agoX /;=bsk$.5js];+ ٬zkoXl[:)}NXmBLV]0~T3Z4:0nh%$*)x6ap v J2&""zckU|EGr6<>"0 ~Z|!aϟ!:.<;? Np^jg+[ZRRf[Ε_er__.2z/ SNP{L¬)*I#VJ'*؊jxz~, +(Pc͈TGKׯVPJQjԡ ta p<{ja kV-xwO֣5#A/Ȧdoұ UZ8 /&/ԣ)04Jp5)ahQr%{B-NUxKm3p:cs 1Fu)T(ąb]  9)FIB8R%(Ԓq&6TUI'$Mj)[JkdG/9'٧f!=xOK> =e\&onmX? "%P2Ia/u',m[3S|[`,F2Ԭ%)AfХU/cgV>j}\,]9*VYujUq0XЅHNOO J䚗^r)Ӎ:ꛛAciT"*SVr*TR=`8sr8J^"ߵ~zOo\V.h=?!]B;3kCK5i5,WQl>^)R2ĺ aU'uUh(WaN0zJ{14b*Ut XUS/O'w S:> A?ch4vvw1ԗ)6.j>ke{=e,6&iyu*U8hʽ\L+Ư=iP8EUJp{:|\ZX9_/'OV3t'IRjzԥʤӫ$+a||TV|vЭ%;ㆥx R]í1WK}gNy,.{m/@6mmZ\-wiZaa&Y\kN#iT SK rfBcRjstRSξ"qrxc px<2KFXr[^RU8A8Nze 5E|x+hrBWzRD=2R.qo C;p9;ddCU#ZIqs&+k *x<,ҍ7i<yվ2xJ\zG-NKTŞxUt}6"I!=,2sTO4ɫVdX:t)O2^¥hT8_gN'ӣO ´q3L'2̒}^С,¬N#V RNuJ8ʸeR^ O9|3Gct&Ԯ*i>Fc\]/ !ĒM M6x5o?ϊcg\:Y~MrH,} BsjWZ`9U)S12*W_pOJ(fTahక}Xt*jyRo?eV_ٵ?B~4h;duI~ؿ1UewtW =$;GʥX*>UӾEԲe+J7x`pSQ?Ssx]<ϒ8?ysN|q7Ou#ƶO>9ou[M(G|K _C`qk]ē1$ҡO+xSs>8׃O[#^t]fN'Կh^][Qo.Iin%7q 9n_CaqJաF[R W OejtK|"a%K , M̢=a܋,(uSĕ#xlqrۭÝHKE->W,^%ַ~<O}W'AEmnH񍡗J%Kh.8hq?e3(c8̵ ̩~?08:[ f*N5iV5GpEz/+L28:y/,)}y)CLvOcסaObgJh<>>A|g[xVu8mttxP-o&k%.iXi&?(YV 3 JQstVF _8<^.c)U|L0,m~$ ?*oW 7aha2Cx|6^e3 V4 ,ulv[/ h𯆼sixK@Ѽ3ZN[zt R(@,T_wTXܪ/[US$J%VjZB Rj1ZF)%?B26Ke> M`.Isx|=9S;^srl+ (qwi_XXI[Y]\Yp[ZK][Euy$V^LnRm H$D]:ӝ:5jR*!NЌ Vb)Fu%pI%*"yE7(+RZ9Ԅ*Wg8фSR5N-h&¿oړ/ fNO  [ğڦ]w^!Ҿ"9SY?uYrķze,Tae(%敓6j|6å헶nf_N-t#:WNQ_ ~i4 9kߊ~xZx>[,~o|7k/C;kW𖡩rچ7w[_LR|H1ʬp ~*2c:sUjG׵ WƭTWUjjrʌV>ࡋƴԹ3R*ubV-YNqS߳h0/75zsx)o4[}*_?$w}M=i| \6j]eKf J5-:P/k -.s,fJjS(VRԥ T%V3ԨӒgUkE>|u__C{4"/>txk\5,Q}3QEΣy$ F&lu+c7,;p)U˂K zX*-:1,48l-,MJSkahE<0lS1*/JAa'z~SW cdƾӿh?*~ iz<%xu|/hAq@KcuuemqerɈP\4r5Rx8T/o(NGR8TAq0|=*8*gI`~C)ՒR,?#T(J<pQүau9yX SH8txOG|F5_ڪ6>hu֑f4[cK}uձL:xXx<<+ԫ_Y\󯈥{:CuqR^ץXhң =,ャ}ebqt>%|,#B3/eNT9pjJRgRU5{؛bo??iߎ^㶭y4^ 5uC-K;Fiҭ< mlPK,ѭTsj *(_2VNUG K N7,MJiVQa#0| to%UXђJέ:O?G` ([ş kC<d}X$xgeE*Ud+2x:RaRqU*`i{O/GѧZTafI[> EJQ`rP jV'c:L%e\2TW/i?txKG}1:fmjW4 }#K..I&즛 Z<u1.zyLm,&uL$r>YסVS湵ҫN\d0|UXRÌO['xrJX3LTkXJރ,DʺxxUU5IRe}gb|] <@~qF_i[PVU_O`gj.R{GJ?_׸WUԞi/ZYeIae{hm)7m:fjKg⯅՝_^-qRI>]7W4 _s j趺ƕmi;xn 3 = >[K`aqr[B4slU:U JaN 4*.uSp2zy? `!fqO:GէaK5E 3ըOxHK4q8u~W-? g>3[O@uio񦙩hu+kqqjytK`o%]! ^Ykg:9f2׫ Tqzx|2l& ErB?Z~/~EO pl)pt:Y:IR*"rU*uӝG)ZS?>\,<k7i|vZmM)[[+ \ʍ ̳(X\n?,N:TcG J;(^4z4RJjשB18ӇF 0ym,F3G:<*䦒)SURRTe>^HjNV8ڜNq:9~ϕC/Ee',9pRzʄ^u01n2.Y&dcVgxP@cxTҴ oS:v^>Ӵj6ejZŮϩ$vq^W660hGuΤޝ7V\"`eR1mNUJNM)]8SgQR~GME[~X^O?i/ںA-/>9e/_ۺ~8V]FIXO xў 1W .lo]OG;JFʑmOSm4MAW\oS^Sy<1P$h~x\/^*y$ 3߅|E~oE{Wa2_iuoo!4"TrѭU.(8SW <ƕ5`|jߏ~|S?_!|λZqAeu随/u%U(mnf15e{i_Sa<JN\"XkUTiюa͆aibjR/[ @1 yf"QB5<"=OJqS^#QPPzCY""]^)Ž\ZZe?y6T\9'R\5Ќ$_f5AKQFIԎx*^ҵ> pvAZWX|Y«\TOR (l]SJ? EN~ |;xZWuOϣmQTV Zʗ3[L0l+UCS)5׬E=ET!)>h?>l=\>SWj0>WJsJHMWըԣ6| 1~,t,Z|WWxѼAuD66S٧L'.](X8XʹnB^ʥ9Ӟ6XF%FVQЕ1e7eB8ʴ9SWU-8ZX/kFGJ /o3p(1_B~uk? <@[,B(7'̳sf^d_Rjt=Swe?\űIo\:OW'O}]e xOf?wŸ_o_ >|m:/wo DW/};~4n/ i>'&oLt߱i+ [MB,[.a9fEOʳO3˱8|l09N/VcSCG 8s+7 f8+w-w?|l3(cBuERJ0Ju!MW^ף&TNBF|ʲxn$qP)AWWFZ/C96G6C~[[|Ni^Rk:S!֩,^+ 5}.jǤfmj$ݛ] P#]Pb';VfxL_0pVt*?B0ehʌUaqxؘjTiSR[J8BU]\u:UeVgFUO~>|3Rixᯌ~7^:o I[ ekZhvSj/&bU*jѡ .i  Z.p 50aׅxTj9aѝx)s%:tC 5TR20xU*ImVj"Ό%R+˟J:,=H¤*syߊgzi>/3xS~5-VJOjiwVڋovhqMvZY &V8<,6;0A"4!R8|5j*̫Q8F-2T}ՊECJt"j=J/aR5e 7|CxGCEUR[Z]c=>k3X]6qtbja,&/}a:RJԩ T:<*Ҏ&#c*>2JQ:TQ^xF"cNJX!P@P@( ( ( <џu})~XW?3:g5O_]K㟋<9x[ºAVfR.Ox\v{T|*09a+ [;e/G0<iI֝*Xac,+V \A.1J+S6q<S0Uq8h,9gZ%Tӎ \t?H|%_x¾G= ž_ z|)oaxuiV0 TOӭ--ETQWcy?Kqxv37ybO7U*Ԝ/32&QN0X\EZ԰*$Te: ; ( (k& UAP-P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( (_!?ş~^~0|ſ&>,q>4f{Qcu)-U]fsNaoa0ب`bic j6ؘ9S|E IVVyG 4x5le 4U熡<4*t!59\ባR T @€ ( (usw%|E{W۬4ogu|}^Ff @(R4D(3O _g4SM.j0ibiIZ[%aQ_^Kmm攄%\h^#_Aƿf6{eBmwO6K4;{aߩB8k u)ъ*ь)QՄC٪oRT~^JvT߲3~ֿWx;?xN"u4d(V?ÒyMr]=gGMTҜ+EMQtΥNqqU98:isI{Er*&QaSkc oR"AY:u>Y' r4+J-B:c4NkQI9EsGޏ2|'?~ i?"x[i5C#ּayh7ڬת[h,xo W"\C+OZu)a+R*7Nz*Te?qnnP/wR2*xTAIYէOJqZ>K(MZ5U7/eS(+=Ihz_fľ)=)4=2i]dYV6p\_ocmqq/ }U' *JR%^F5*ѥ)BeFaqxڏ ,F*ڕ(ZZΤy*TR*TT)P:`P@xßhrA?Ixvb+{w[ԮaӴZPX%K8Y Te)R+5 !JTW7~n0KԩNUc*O *ӧEWJ#Q$xO7BG[.l+b.h4=Fk(\7(LVJg85QiJQ'q%%xGFi¬(Өڧ)+*K^u9e٩rGx=kχ-|5xEoxcWtמծe8-Y.)uk!"LtTR/yHsJڐ無(BJQ ܒ'T.XϖpiJp&('&qߴ/ƚíc^6#WDmVeKxLBaKǔRkSZRHSVZn.Jѻ9S焍&)B5N5atҔ')6$p娢8JW/jįxĚO_Dt).Ŋ>uMyei9"#g5ޮCC֐:j! J (UjaF.!\J\9ZT'(ƵjuS佤P5j8]0Xuy({X+zAA@P%("iHaYe85/$H*"(,*$53)u*N429(nScܤI&VmmJI-[odSwWŽ7X~x:_OUռ5[xKMKrO}O MF,f MV!R XtFM.z~Zr=7*rÄ̰xf<,jUhj*ԜS^*Tjr֥R 1|GO?CO{GdžKY/iVQc̻u=Bk{+;t$xn:2bЃZӍ8)NJy8:aN (MJSZHQBJUiѣB%Rjf)QN2VaNe91xl[ >=5/n>ǧhPQ0[]Rk/84K$jeDhj`3 {<.",өn:&;UiӌQZ#)TIxW MlL*TGe.Hӡ'QB%jq)KK/+C4? G<jx`1pђ(+¼RsW%JJ5(V6Ҝ!³LYL84Z8oWZP҇Qrw^ ʝISFi*?C( (c[[:xF񷅟R4|AҮ/k,5/Py7qu][4){Y淖9ѩ F 2iEV pҚe\FFq:SI~_年+\ŽSZ h$ڧ|M5I"AuF{{Xy6̸+xUq_Gq4pyMTR4*ͭJ:PRQEZQR>b1T0anzͪtF뚥IBk^_5+ÿxs"z_# O4I^L<ٰ]yPIL;}GG*pYӣR2 QiҴiC)Օ5JJ2e%|_T0X<*bѡ ei^ԧMJyME-|M x+ASh΋lo5xTѴ].:OQ##j̊:FwUj*/QQ]Z#N8''RmBRr R iХVjСNjѣJukV6ҥJT!NQr 'ƞ<{^y,݋8>4QX;SqR GЫNУNUjTm)e "ԪBYS* T(YTeZ&UJӡJ4jˑIBUig@€>{a7|0w֭:ε ΣmJ6#kB47L7E4r4RN)jR2T'uejJpeÛMM'JU(2NpSq|B% E72vrGxZ4];Ğx{XK']u+=_GZ~a,w3+(iʚڥ9җ%HJe$g8I'g Fp$.ic ¤y%(Q(Iq}T88)EX{ ..j6aoh~, PDe拫Z̶:;:k{qR|>F*Pa!$WJRJQuc{Noڭ*1-Zs_ ^%գE|#tRFQR_kv>+Ghw[d,4/\x,nn[{y+[y,QH!9rBS䄪O.\ni7\vWzp'(sIF!{^R%vzIA@Pk=:P.l,xm--mѥfH`i]#TY֭GJziУJ.ukViҧRaKId}_enq&߇ <[xϩjD> iW5V<ຉ.[K=[Ԇ# Q|lmWմRziMFJ2.#^8Q)ŤՏ?/rx.aG [^&q4Jƽ'*U-N)Ҝ9&|{ |7y0灼-`EuxXtĞrVn9n,nVK! \vN5q8hN~Λ5R+gR'>Jq#9F3fNbp<%WbRᨩԅ*nz҅*|jSOqRy|,?g 4x~!X5hC5y7V5kKdn,淶L&,&=Tx,M W=Xѫ ԥO4Ji8ATc9 J(+vwR&&9{*RgW)^2[z& II$9$u'WKj)MF1MM$mdZޞGФI&vIne<>PVm5IFVG+4mKuS([i 5ݽ)C;V$145)ƌBj48z9ԧZJr'fn7\V/,*y =hVojKFnjԢ(եVhӫ >[@P@|Voÿ /z?-o?a:eΣyz4Ȍ։eeyjua Fէ%(΍j'EP*U9[ITZJ=Ÿ>xZ~~"AOxZw<:^K @q,p0^R7S:U%NqRIRSTi5:iRR*SnS&StԤSuy NSTNsdV(( 5#^kM_[i^clKCP K;X# $E HA5'ЫץPjF*p_ju&մ۴roSSvI69|BWO i^;y=7ž>"VN7WHQv۴,YBRT8l>.e<>.1zQUZ5aQ)$]q`3k[㰮"q8ZBupau`NaZH**u9BQ*gi|Hſsq'[DռQY67G,XR]GQ(f>;cWXo72eѧ,v.JQjWW4F*Gߚ A9˖ ~7p\V*(aʣjgZ8ά-(9)T)Z'~9] ~/Z]h.j6Qph'/tx} F'MsVV_%^֡X^]O[wҭ-lxnu:Bk{M6K%\)bW2U#<~,Y'G-6]ORM*qUqU4nLEJTRgC`2FSbcCbҵz!:z2=:[@P@|TrJ<-jCP59xN-ETN~I):rN|,Ipn4e˭ ( (?( ( (¿hoٷOlO./i':g>'|QQ{qi^Ci~x$ti!R֡oZQߤPsW5pkԖ уUPaagV5#PEUlu,F*PVEU|=,e2P;-y*teJ62/ |uPk5SzU!߅ sශ w/i?ZA&B[M6դK˻]홮%ahիOW4^4t!)N|-Ra(AXl-8jF qN8riSP)qګ|;^ۼVzkV7)խRJ)K殓@ ( 1ɣGy~T@~]fς$Nb*՜p[+Qҝ:^ʜ#N?43%A[z~OlUj7<9Nx<5J`V_^FxR*~8y?n x~`S3A<S,YIBԣFc_f~P@ygş 8V^xC?ӭ-52٬Rzbe\-cFPƌZ0TU}+ KF^Qsqjb EoG үR:U˥:T*Z^I~~m|yW7v->)au JX70^jډM]Bk^ܲ՘gĩԢ])_?,>:%Ry#&nis`hӣA*N|V2of7WzmJjQn|RU$HJ; (*{¯ M~%n\Uݶ˿jӿG_P7Q Rx'vMOiI#.fҬ5! 엱ZsuJ լ1uHrxE<Y^& D(SJ0h`IVaͩa,& rPc3L%jU:%VRk_A+ ˥Oэ35HΝ ҟV CZ~M΋{<au G[ºq4ƩN>-G8"V;/#ROjWO)bvYm<%\P)T 0%OOG% NRY""6RT),1%_Q'__C?47~ icirbxźLwi܉7%<*Qjte QrFab1= ,KFs֍\~9gTΝlngJP.#S *Rj3)JX3OԎpP@*m|S߉k٬4O.f>.4 k5e6YxS,(\ TXqRG߂NQv3k-{7|{Y u+R:u'ʔjsSjqS%zp 8A i>6;=;Lu>-Uomkmg476)Rj%VooVYΥJVA9ԛ򜛔maRCF*0ҥN*х:yB(#/ßV|qcj>ԥL<+y$Q^[lּ'hݺ-1bb=)5DTJʤy 4ܹyF*үR>άgNS'!VtEoi U!Q(ɦBҵۄOSi|=m3nNg-Z 7wwuys=̳Msq,9w5ߒթ[Tiq>aS>&:qcSPc*1J)#,ʔ)rYGʶ_VS)Քe9Jrrjs;G%͵6Ksuus*Ammmm,J04#*F5jӡJzӍ*4iέZj0N\9)M蒻4'VpNR t)sj1#)JMF1Iݒw~؞//ot߃x 7{V/k<" zݼ6X'^M}Af:upO1T&ϔ3 9f pqcSV.E%S/,F&8h,>yWxqxL3R\Ҿ[K^^yW#jʦ!U,(W( )4^4kGjw׌d|FYԫR:a ԔRiubxK1Ւ*\(FE^)R0V'*ta^J)B(۫OQMU+ ;0]IPbB䁓⾣\y 8-9Fuyo-^j/eJd87k'+/QM |zWO5/[6\YwH7ie|=Gcnm-?F=,'fAc?jX\NcceTȣWNRtt%֧3,\)th>/.W\$)Sj)iPxzӕuRW9ʟ-BT|+7Ư? oi^=Ҭ5;Z,jV(KdVUt-y5lrƯG!)J,_JhSyAZ)RPP=P|UaU:X4ԪWɢYϚ?1):xkڪ6k~)9xEΩ\Y7^kUbX@$ԓֽ.|9;yF:Rz+\G6쬕{+vW)aoJ8~6УiK,(N&UUVYQ~'8,/ 3j9cs V<6aK_/fC1̰'*:t' ᾣ"j><֬t;iS_JkV2/c˱oCG*6 "3*G:uB_=Oohv~𗆿 t- OǦ%0S5 k:Yb+tbPڳY1,hdžsJ Lc:\N0e9sJQiY%lDV9 e)J4.wR\eYn_kO:[oM⦵^#-`*30Y~_\",0XO̯]RsOx*{vhsrq+Kxµjtɵפ?:Ŀ5u߉#Yu85f$tߴ,Ț<z:igThV( x=ʸj<%˰OW7*㰵q8ԔZZZJ9:j歉T[8*10xuMSacet0𓗱9](*oL6 EjJ엨 ^_5մ?CxoĚ5t{YmhǓJUcBu=\6y֔r3:+թNB*NMKx޶+Rfqgv663lO%xB^ux8i+%ڵOts^2GhԣZ8Vx . Juq 03x1 bΖ3+ekv#B#z'Д]ItqrRXj\O_v~-Aw m|X[M\gIӬ=Ė4~[Znas8a^3&5ͳ )sfEl=gIp/%R*au~Cs<5ʵn^4dt+ =i/z4qUs\^'- D}#Fqg (~7tA_|>Oi0exkP/м>iw6wb[ozM@i<6_.Ms|:(!V|.7 4gapSV 帼JT%Jt*<X:NZ*50e~xOaK{|7WMAxúv +f.5R8"E!75%W[ۚMR?2Svg#;l58n7*8CʌieJ)bZTI{7 h}P@ez6-WizQ[^i2jv^Go6zo4wk}k!Y.`#b8V:UpROԢ[Q:WQ ܡ SNeNnHZJ.-~&|Tw_&>x_<@*u5Tuxo5Mk:ƷOȊKd$CEyZL?5Rንiьcp_jEJ%Rn򟳅{Fxs,QRrNaŽ;ɻSUpmi{Ǡ?h_,{>~ĚBKմ K3D$-[ qQUS*\ *гcXyUdpweT\='Sa𔧊F2VqjTgNMrI6l }?dOxk>+ѭmc?jxy/.Ou%x'Ԯ̿IhaeE:Teӎ>Σp4q՝Z|ΤR7ZOc֫[U&_0iJc 4njb:vH_+W{D_߇.B3~0 e_Xn-GP)m *ĺufN"0|nQ2&/ZJVy ,MF42zڲg)WqRw|لp>+g(alhЍ:pXajR Uo:R~E[ "x凉h ũ~ğ|r XhkM-3V-ƑdhĦmyqio hFtiapcM)ԜӡCFrJRk R,=98DTמ*+1v"S-*J|]zԜ>HӅ,4֫%rTVq7"4O%xB^ux8C |֟9q1y6\9`1TO/z-wl&720 1N~Χ% _X`p'^YrLo'LF"?Ml'du*2:1:_൚||)!╖葥5-Nu t4.o&%Ϟsk7V_#)2HIXR9exzT8xZxՎ:YU|40YmFOr\!(as<=0 ҟ5,] u(fBs*+_ ˱X9+c h x>8xJ^Kӡf#G7.XiϭXZ?ExϵH_gRQX)Cx\- kUs*\V~ 4%FJ1gj7V51^ Bz];Exy?|'k #|?=yuV<xuM96+˫= W‘VJȚemdחJ :g9J_xn.YVbg`麳,嚖+1J\޽JLꮓ3ua )xCPhҋ t#Jd?|.QGV8ӥy\'`P@/6|wwşxB?|7|W5Ѵ~#4mR"鷷[k3h%kƎ t.PsUz*UU\JG )aF?k TU9ns)|u 47G J;JS4WZX'(uPT_a?ǟ[c1nj)RjX+\+SFy/ ~1?~GD_xM@1j4ti:rkX3jow/Z DyaS/8<,>}F F_3rU)'*8Yf'~ |s⿊>oKLa#4jڵV`%--"&I־5)ZJ. >>/2j*8 N':4N~ִQJ*[֧uqَ&3a:PJ*p*Q^hխ8S>,Od<Yys/!kO+ AI{x{ILgIcxDxC0Lqy'k͸n+e0T2|h֯8hb!3lu\1+n ̩V,y\+JGa9N9TY.jocphaaEЏE_Z@P@|ψ[[éicAcS.m`iOԭ^hLdheΥ(UQSMR}rR|]&-$mKJUgFNtTN'T\NE8*NI(.zrJrHgO;`Ðxc6ڂ^jzKj }w_j:%{s,&U':x,sKZtJqyת'oٷ/4dx}s3Ʊk!񖅣x].d>eH;_xUtӱ"?_rLulRd:Tݾ :QQubs EHI8*pp—Ÿ?'˱t*O AJ, b Tju%,8\4oPiENYK>|/q|h_O㟋^4>!uOG6 xJmZiv:^s%Ր0hqi6 0U_cNt|82>|~2 )֫:Yq䣈b'_˥*ulF2b$Oة)N<<ҭN)F4eTob+ ~xOg/ovcuic#ֵ3.ۚKy#6a5pR‚˩8SB%(B^ӥS FAjם:*s R8BSU%Jxz-7ď7<~7auOC?'rOVNμ菙?iGOC/>"h{?> |">Csq|!5ʰ4I7lB',>Bre B7Us<ʧ8 5+N2\5,n?g00b1U7 b\pX5{8ANcF N'_a?g]rݧcxS{{K-OQ(,`(a(֫dU1:2{yOܾXZٞ&uiᰘws+LR|HdA/o5υ?$dž| C߉6ڵƱaϋ>+j/XD_?IPԭu)]|̋1JksyxᆫNXU2UaJjzlG<_W὞ ./Wc<;,9 j_Vxo%Vya&ӡSu+Ж30N?.~ǿEj?_oG~ɪrk7][=b[ [}˜Qwt0FRxy_`yۍUc)u09sga8Rq+LZO=ʔ sagV_#CoN" eG,Rx_ B؅# >g:|F P^4cP@~D8_^ m ß귇?䠯bޱ (BSٷEtχ.:?5-үngZlzO=1u ]z_oFTAn#g%4WQO:xz\*eX2UQJR9(J1/}J[F T*`qNTiN ^abՒ?~|:ӿa5=5:6/3C <sz6fX )}m?dY1VS3'_N SK YSӧJ8% R8/~<`c'Zn֣rݻSHMZf{{[i~94;<7i7skOml%KbY@Q6 ߃qvVRQ]Բ紴SZIs$50̩—q%*rs*xJpfE$ݒZŏjXoّl]6OSDEd~5~`~ 5;c-żOUVt0KrL4:ؼ:v|rR;k/"UqgF ԍm LӺTpɧoQ'ΓN|J77_@߄Şïic!x1Z7W,t[DI4y"Hnt۸l_a['uE /0R,adh:i֧YcQQqU)tq(eMZ9l_B B*Sj8:7,4KJx^gCgsտ ~;6~)+ :I V6ޕexM{+wHXַ_l-.6C2MluZ.`Qs ~]^-rFuB8JtSs\Ζ2]e,ҌpZY {5v2<%֒&.# Uԍ=Eݪ5 ( N/YDp{s%zտ?"> _?k"_!c?'/6|?U_N޿nǗo߄Z'ï(eU%?; ?:]:ͨA &cۧ ?gW3e 0 tdU1Uga+ԖQ1EGYZ:GVG/Tէ ~&Q9(T R1c9Ab冭2VêVpjyxA4o>Yxh~5[KT#ge0KhĖsjÿ Rn1sJ"%zj^2lCFIռI9BիЄT8iÃs̲>Fpҥx`0xxC|ҧxU"f>"Re>&^?'> }wo<Z@M&{=73E4lT+bs 3{^XJji:UU:N|R*n!)*cQSmiV-TWٹ}ЫMPh( g-C-[?oC\78os6 vnoIMRҮ23, {WS[%(ҋZ^aN#I+FKKI߱ߕW4q3iCדTib)ԓQm[l~Yբio =?<,G RTѸ 񞘯' o Μ,(gM=([Ps\=hJj5­9YBP4TRW\ndY]Gρ"\12HtgvP \k@Tm~bK8cҒi`R/>N'l.'D޴*ϗUM1%*v}3)^~;|^K:,>cyZ5=B֦^n8_ٶ*2yG,E\6*{jX:QWLW$(Z3:YL**3+NQ:tbƽ*OISr])S rpJ;_ǁx{áHn.o[ŮOcn Q 寮c7O7vJpTii}[/CUUjjVr}}PT(B>ũ(yЭ'TRLR:XlZP,:%"B ( ןw^觯/<.obQ*a(_Z? ?j?j$rH%o|?[% nZ߇gow$: /֭p**<&_,]l=kElDhѯO,*ѝN+`¼kڮ2<ҒSF|% F'C¥,F&c)Æ?U~>it?9>K"׶qK<:Fg3iqelEDJkjNiGVs,]:8ZV:1tMVY)8֌jFp9&7+2+$pɕKaa)CK VҥItB7~Tſ(x/G]Wxs"? |܇T|~WڟP@~DC?[3?[pX%s/VqykOzăh X=5kh!veiR4,:ו ]%%P e^uS$QqS!W9 JrWMsF3r2qRK8$]-z4~0*Fw2J9+c(h*uk]wWM]uMt>[/{kGT1-~z 3gwY!D+ VH p]' 6kçjkR1[(<uuxu%6(ЎQ SqӒdNVw-n~~On)47* yHiZ'uߪsan#ᬊ>71Ÿ$aq*4VXnFv*ӝ9R*rU#4׳_(:աR xK4 vekE " vfcal@ % t^&7Vb+b*rXJ%R|F*R|NY+x0|,\)QS9h995yIsn΀ (Ͼ-*djUm$g1zOr`&sO(g#W?WO~)EfP~q!xo/x:퇆%m2W׵NS ajyjM#9',Qf8 4c*')IBR&YBJ3^ѥ9Jg8SJjSF*֭8ңBJjͨQF'VY8scHO_/t[?> x)( ?%<]kuE%Fod>/$Qe\??G˟އ7d#MI|)fv t=:Ms`2ӈTy%(W΢ mO2k}!G+ש&hӣNu$F-kQ),o$#S̰tfJܷN)ZV!{s^ɳʿL mv{ZѫWOUx3ДdE7~ֳGo]r%Γa%y{ $A]k־MH,[IlU}k)Ei]4S?e9)N|뒵)/vqg/򗭗 Oo.+'پYZg{:tg{$2xW+_*AMľS4=G*,iXS>KN|&_Vqu' 7uRxj`UHu`x<{lux7,5ZؼE6c/gPW6S ՄԽ[[k{+k{;Hck[xPG PkH8F+z*VRYʥZJ&)Ԝ97v)7&ջsѥOF 0Tѧ T:qPwOPhP@yů%_?xQJc&3UbC)Yc ?=c^ 7uJi/%3(Ԛ?d8?< c^$#_߃)jwDcrkcclu]NH4+KIouB)'3e8Ib>K4PSԺr^4J*QZbXLh*21%G B 'R|Rr ThQWTѯF,z~ۚuσ| y{{/ 5 fus?5?g6:徏j=e"+8Ê9j*8,"UxR0ei\Nv8%ZT<3)a0\3M|WajXL3,M>l~eAcs >/i*xj|xiU& pqX&ՙmwXฉfxYu-G,g)$h~**աV,ԣ!·IlVq1!ĥ 9[AY-z(z$ݭtiΤHŽmc%%yb0,۩[Ⱄi+^u*ׄ ny+6yW aY[mն|gmFA]xV_>}ҋMtg`]V?z5zFqۚ({(Yl$ѯ/ad(5Kzɲivفеxp)-ʡڞ7^c%(YZ+Jpl87e4ϙ]rV%,>RZ)M%d7+_?࠾6gRPt_?<5~c*j~޿g]»ņk\Ii{v9qfQWrnIr)By<i_/3釆YԕZ9_TIg.Ysx&ESI6:UWդ% 8UUڑ)$I$Z$. a@P%d+|+׼7q_ys/A>*~ן?hxھLpi?oYW7<>%FN4d(-mb^ f옴 oLWIuoW[mtb7SZ[], #b(r̷M晎%*V$ܝ(Q\MiB.?ʰ83R} bqp ykS Th:)auBo-C^ _ESऐjZ/ >om]WV:]ΡGյh/bmfҵCJZKd9ZX/ϱnE \V+dyvKԢ)V%_𙅆'0̔8?< ^$2378w~]Pis, %\r,2]/?k?_7?g߂W]2/ |gP ilo!< i$ԱUc ,գ ' ю_,Efx7xyUa)jVc,&:xƕ/gkb9GUsg B89P"9cǺy7 0t,:2s u˰ج8УW'>_ ?|Kwi'~ ,u"➱+Үx=&ۦ&7:EGk*?!#KiYb2 & tUJZ5URY+V#B Bx* Yg8ee 0+1b+WjqQ/o^xÚ#ҵ 5#OE>qIW_ٺu^oٵ =r]ogRPS:R4jQvMi(qwB?K Vb)Ƨ%ozxR-5(Q)nVgPP@!a)ֿۢ:Mgo|7&ЮA|wy<=pl-|;O ҿǑocmÈbsXbժqbp WVͻK]>uk%;AIRAXU~ ފY>Jl3,+WO+qq|N*7?7(/ҧ|S:XsseE9*W nTz1[g^gJ][Rwh|!|:wwf$>!ymg!%+;#<)Lr\︙*U_q2WtMi9կ vZhbgSN1V%Z~g4)•,L+PӣFNaNUV 9&GOw~ԔP@P@( ( (~?K㧍~_h_o.\iqu:zK߬i?S7¹/-3ok'8[k~_1Я 4֜pm,FX\M(QQզ)aq^T<5L3lGЄ1 V8i*Δp'RUABO a0ǚ,*| ,~_9K~_ <kyk2B<xI/#2iǟj>45ѼYiW %ėk+*J8<^fldƭ\MLlUB8B1Єp9)lfa'J\x?yT(eu8כxny*ؗb { Wn{u(ki^anHT3tV9֫:43RTNSnV:qj\yWhƄj…WJkW?ccU:jM9jsOV-VF@P@~M#Jh*e?9k/ؿWakKxW+=L.JlF6S-tinV[]7Enb8+^gnsxN`QcGʪa[ڸ)MQJSK h|poĸl*2<ʞ| 2zxTx,TS0Vpp"apըOF> g=9O4Eh[_z_mOJM-$[_PY]Z--ͼH.cө,m|O!XXUmeu(­ju'VG(*JJe[IXl._(vKᇍXyVGU:ҭI^^EG.?j_?1]GJ%aZݿtodxY?_- m;7{*y:Zra*уF%J|WY9ɳ<ӎ\ qs1-0z، 5p1YUaԽ'IJ ?~0ּ'n_h+<.4Kygk>MYfbmfɒ.yX908x*Ҍ\/!VOl=Z(TW#SJxPiW ֝?m ҔhW:N(q: /m~֟7 |b ~>⯋Zz MkoѼP%&╍LJI%nE ә+wO'2:=R:x˳ Άe*acN2|J~=R+k#i+g{ d:-ω|/ėY^&on<{Se*]g(u NZj#8(ERjJNjni(ZZFPQ79^IsZIK揻GWj;+#_ 7amk#Q6-5ir~FF|mhX*\]*N[*W=,D#(C FV5%RԜFxq~C:.ȥMEE:.I%5i˗S~fCY|  `_JD)֬t[숯:VgA7m?Xajfj%u>URn\JN>ʼ%{T)W쟶U)va.e'7C/ⰸ4ΰqҥ\e6~?><4o>Ě ~.aku}wnk ߚb*^2/n')TŪWJ.Ur˗RFXDhEr?`:5"}Ng wNԏ3b?h~Z<5;MKħ$zqΜ..P侺f[\𱩆`sj`q 8u(VU|\=)Z<)Jn{UaMC !ZJpuJnSiA;$}}e|]˥|ae#/o9ĵKPK?-uM2}& 3fVL R*]x|RGR:8W:>֪„)^Yn6GX%ZJw_¬?eV5V܎cP&. xr_ kq?gz[MupcY~ X~2bڏ<1xoVG}OQ-,Qcusrsv|Ok>ʶjq FPU)R Ƶ T(ңV aP nSr'(ʎ7Kӥe:UիRj9+TWx7ֿl:m[uxڍ1[Ek7ֺdm)Ӛxۍ? YOV(,-L]e[ ̧S 2?iN%Φ'Jt .z zΖ "/Թ]SeY7:iBz.IFP@+oZfk֓QmWTic(6[ȼw1hIGJ ˣIK.TRRfxZ)*PQQT)M˗^;2u9s,}9F%Jbҩ,<]:_c1y)**~F?wkxcuoÞ1[_XhZbOޕMӵ}'|)viU, qT/O ?mF+ ѯkrC]r>fucp|[7-R>UauTV^FAx~4 xkm{-K<1iPχnuM>mZ7ov[^2LV*x{<:F4:^—eNpp)r׏0xZi)Vsq)ҥqQnrn<=fr%@xW㗋h'i)?q:,hZ驡'x / mqc<7Wou|SS0To|V'땣Sߔ<:qe%욅7 q50j<-?eAE OIRj\НKN2~VڬZi[k:ݾ4ƫQj:DwWq_ݬQ{vI*-1#i^TZR 9Q:T97NSmSsrFtR4Uj(:|Myh+\?a<3{Z>h_&o wiփRn> iT-q}62W63c01Y^WƜ"0>5* n#INgՋ,V' [úRuu)FYN5Pʍ*? tO^_|Q   = I5UYњ쨺27߼u#V%RdGʍ7NSyӝU4*T)B_k[FUӕ:j(T_-YѭWFV4~}bjP@~g|z:~τ?|W/hއfq\iWr|EZ5⦟8L3 \V1UW2R)bU8šυ^0Ϟ W`Utβp|>1j}YNԔ{憫fkw-Pifܗ3iFmkiFuԺ({E6Օ|n2#cN>w CJMG \^./([ M,6 +pSru+ꥈj17V'}YP@|miYߣ|Aw%~(^mK$gҎhPqcߵFkxeǏe%bp0G ƥJxUJ5)>_a6M3̨թV&YN#j)ǖ>4fNin'eIE{Ư* 3ӵφW6ƞ+^ IZki^,_ ֗XĖ͵힞ڴɰ8[nW~ 5zKԣ\*Խ9%% *իiXTKw3ywBt3,ΎgQdW \׎gJFxg*u#_ӿm?ؼ1"|[7*#D#>Һh4i>^._O#2UҖ>¬dj P &U$ԣIJE4 sE}.H<si[M:o&{Sg'kܘ1\'c֣Ln2%T"*|E:lBa8UyD?73^=RC:0:0O0 0 Pg08F0aȡ$yG_^+?!Η=G/ׁ>vֺE|QǪ sb$C.yX \%W e7Eσukes6KmiegSüD04rZOi 1T4iΞ&05hΧ/6"J҃Wo>|oˠ|1[@E3>j^izDt}#T?ڣ)6ucsX N`ZoS;r;/W~ᾥ=xL/B 92xYНJ ƌ85<&kc+ujOFhbc|?RnT›N)]RG=|H/+&:j[x-.4[$en<'Je|Tu7Bm Wb16UܥX| 'Kh~|gɰڸe9\MXV8H({zXW,7+ ߖ_7_+NoRC \ϫj'%6'K|kBN};Et:p=s\eO9W5搩usjxXЩC p4b~Z 1Box[Y=,s,Ry 8YApZ#,;L62|5lE[.T.h%pahzޅWItWV:A\Y\0K IWKFek9?h|E'7z_-'IvM&_בj?nLvڌ/5^}S_FYaE],]/aȹR;iYV.cكV6#x8W Ybե)* rrj :-T{m~xWA__'$j0iڗ#o%旫1-GM>Ym<5L9bSoYF78Ξ*0QU8<cAƞ3 ^V{h/a4$<ڎKSR*Y s৆[KUq.8q%e 3j-;kTo| t^eM>?TFcwkOmm s*X|}Q׊+c' ԨάhS^`8l>^IV0kF)f7|>&J)š)9u_bG,Jm͆>M[vxq??[-,1eyʞ_}fuWU|`'r. 4:+R_1aV):'KY+eˆsIfN*^co11zTΕ չq>֍uNnm_?lx Kuσ|ھ'rkȾ>/c^Ggl7RhH[Ԗ_'5^g#U¼$i,,<a%R&xbb+U)UԦҌ&o,ㄱc`(XJ1xmcqvPW5J?ScBseQrG{-|y ]YɯKĚ5M_k=Wޣa*adXe?#FWzU̳Z.2Ʀ[9PŬCuXtB1WB-ENN 'c|+nɌpyTTFjR(URJ9JrRgſ|^Fi./'jxɵWkm*qP˅[&Ɔi `Jx:xZzʅzUj!Nbc:u(#^XM{Zc0ط1X|~J/A`ЯJ8H*x;EÞ?3AiMy`?k^}{ZkR>T/ qqF?Up+K=$NNzqiWHaf=SrysJw+>7Ÿxk'o~&o'%66W7V ڤ6-aEP6]RJR©SW _/aըTJ0AΧ/jT"gWN1\kʅ%z8Zt({Iq`iTb+h֔j,u'RJXu^s\jrǚe3jgfo E_j^"2OŚƽWºχ ^+Fsj`爅8Suࣈ *JPN5XʼZO٧ž#ǟ!xƟ>$j0iڗㅆ4N*C <𐦨МW^J37|p,&]ZX+?jZx|xx^8ʮ'Z?c Е =lυߵ-i#᷆ZOl5Bm|GjZrh}ĚƗu'ۭћ;,V]ٯnw`X)G%<w%J ,6 R3y{JΜ_q gڸ[NK㌯uiXP){%R^[dj֗Ws?U5iz-[^_iP $3Usy# ^4U S,b0c+RcZ5ck(RV a8U>9wK*Kd GOUӭfqXJa:8N t*kzW}׈#w3 wς? xY{ Z<1W_>u%FledKYFͲbf8\Ά`{\"tV"zJ9UJIQu)gMgm<⛻C{=Ȍ.<;.G ^?f poɱTFZ2r?hJ*ygZjQKe)3䖔N2n7V.hͪ8ѩ;5*ʝ'(s/S~.t1ቯO㠿1B4_/XRڅ& taس" _3u^ȩqa#euA{N~z?Ows}sirX~<:Ǎ~'#W x R ~wM:[;v01$\̳ilNCt π+5%V5#z\q(N5)Q:I6VU5^Qx%N^)~0ZOatn~Gt|G))}Y뗺=QQWUM5M^ٞ{c2,G VN 7?kzpJF4NQ+a)P':qbkUZ卂qte8z*iqe8VZMF/}2~?5_~6|0M>\x3SjC@,/ӮukAK˦鵝IWiaq,/ʸxS:F 5iJF(SC Ж./ V8n"YY(F~ʪU-ʌ~Uk:xfb~j~*x^Py _t5V{M7NvVﬢ%S(l\*TEMQZdg*&SQUe9RWp?9Xa4xIգwNUlEJXe*#H-u'K֬LWӬK3,f)MWvX-)S|d*sNjpy_4}>Y-%h5chfXcsxl~ ùӛ :. >47wjڧgAof<5wkfu B]BԴrK?NFݢQ=eX>sTpNRG6$Ur8q[9*}epNx4Cs0'[PUSrЯ2P)`ƒ5G߶=IҾ|c{OWOꚦr.evnt{uK[XH݉&&9Ev'-c#U8օXӗ*W%5'RtӔN[+q<ƅZz*PUQ~ҵ*U#NR̒ aUҌ躧{o*?oyĩ:w x3/O/ujNB/.. -},VK,{2  ʵ,*KR3^ ZuƜkb)RIM Vplc2\3YazҡѝZV*4~C–u/ॊwZP@q#x?oH^hq$eckx˟2wK]?NI bT ,v"zN~JSJ3F8έzΝJΔ'?gNN^HNQ`E & SVЄBZ TjR]JiQV!/|4w3Gƫ=7X֞$џǂtH-LZ<7xvo# ;/r&žjPVeIѣEV5W]Va׮tiR4Lۍ.j5x,/8W`PFz)RRUxdk]U/3Ь.]k\֯'I,i5 GPQXTSBZr"u*J4ӊsRpN2L pVJUk֭VpF Vzj8ӣB(Nj%tBu*J0|CMbm_Yt~3%\WA[#O~Zwt![yUĺusN8q9ӔTӣNOTeQNXa#/<l'Fǀ68*rx7jr_iң%Jy*,񧄼 mW2&hv?z5BG%9澞E,0ڢ3Iwq464wf&SB'2 3::J`ySZBg^y*s8@_mGKQ4%*Ui 4)JQONuWJNJ>=1|=/mŇuo'|/KOx_H+tF b'31xpץW WŸ*ׯ ѡB"hTJRR':*UQ0Y-l4a,BӯukTBJNURKO ( Wo2~~gme`w _{.ZxoEHWXC$ZzZl]U[yoj,vcV6xʭ µwN:.%TiJbTVI(8JQ33YNSib O.TJœ:ew(K (9x4ƾF#_/xH݇j..H ۬?á}w6'Ǜ\KU7(Qs۔yJ*X1|%)b1x\ iX4۝^kzvfZq: Rc(Wٱ5e4Wԕ5TpqԨR3RMB1'V-8N qfX>ScLcp~XCNUj*qaS)99Ԕ)FsWT^C\ec߉d (:3Een%eFK*c8ӥ`0XMjϖ tah׫& U]*(QU%Oeg ,uN"RMN1Wa!({)ϲu߈.>'xWm0OY]DKg,0JI:iMxodVqxzX|%gB"OoFOm) *҂x.h-"{{$I IhX^92 ӜԌ8JP'qveZQZjQjciU^:*SF8UZRZU"N:n385(N-QiL( I6ݒշ]z|?~>Lj~*oVwK[Eu Okq-iq1yj[ y`kЖ2ٞYScs\f *N*2փtu+QRqƔƥJ_3qps\5*ђїֳ˚qvӧJ"ia:RfTϦ Yb)gXY85/$$qƊ]݈UPY5j԰ׯV)εjէtҧ:jԛPN"9ɨ1rI\Sasa)JRvcw)IJ诡!狼_mZ^:}cR׵Zwk~6]xsP-%/NO1-WcK_eyua|>#Fa:0s 3n(ԥD(bUl=8+׼kX/ Wox]"K..t}J+{ɴɭ5mn]ίLk\xciF5#̩Wtʕ n+)ԣ/Qr(ӪUCS>hG8'/dcphO6?ԚbmJ2U՟Vi_?|Q{>3ԮFc]K J ~+=Op(=W,+t;{;A5+K uR+CO~o5 6T]B;6̫qyx ~2ǥ,.,bq+c'v,R`#9xF->__2>l7dv/bYTFu)sapY_1ˆR?a]P@5"GGXY"" UUPY8s8NIƝ8FS%BMscI$jNMF)RiF)]I%vz$g0fo? 'x?tOhE/5-~owk=o-GkqIJ׼U -x JsO"xo^&Ѵd:Wmq^T8uJ53:9~2^%VBlVj|f Wҥz+/\7ᣎq)N.MՇ76W zX8NeYfQJXE;#~~_?h񥇌toM$LjTK$gWSti0E*#%(mVJL7Ku{@PVj_~!7ڛ|O-/H{peEk+;˘5 & RDuJsJ*z6hS6da In:BI>7tSYӏ+9ywh~~P<%yz=\Kji7QXHCs@kyĐE:5iVEf) |4SRkaŨQi)FN24+ҫ[Fd8U%ⓧΣ)AwqWgVF9xG:qgxGIROzfRO 7ե182G$WjէM:jRJs[\#)$Q;Y9;7Ns!9ޕcz˯+vg> ZM 'ϋZ՝^חV6gAn8dD" 8汹 w*R9bpXu'S O Vyrr:*ib> T)%jNqPu D%(N0rUaZD|-1ޯk]M-;SEjRiwezoms0qq{jKG )TNX6ˇT;V+;㢥RTkV\ASsI/U5nf\rq\i79Bx{}%׉|Y?<-Y=CTZa[c/:ǩYK嬆4Eݘ|5lV.yըB;sU׮TzjU5yхJ!7jaձuJ9MYJY$(Q*W>ZT ֝:|SՁP@ ͵ZZ-̩M<0#*FRSVRi$\q%Rj1Srz$mJsy_}ſw\iv૫åKmau$&t,jR+;IZhQV2W\O Σ\T0jשvJ΅gKrJ%WJU(yjC "cSBxE5):q?iyNs&"€>GkI'<1.ɦBԾ-x  4tTۭJCu7}PeN:1IG0C?g:[>zq(U:U)UIӜ'=*R*7<[g:U!Sܣ:qoU!:jIBNP{33J#E`.!+5w6W7Z:^k'uVvwœͷPZZZqJiSJNQ88NۥZZkRRN?#TtNX¤^nH?)ҭI΍HN^{SQ/uɞ8nkyMS OF:Zj3R18Y(bp_Q:bV5iӥR0Rt V)VT׌*P֥/9FP)5 jN1zP@W/uާ?W{ms]`4fɮkSIoo)#ђMN+I:c>EJ5G.ImYrJz;SVlIF%nNiUJNҒ\<LJ>*xmB^)iҮj: Mc3<y;!~aaeN:l&-C2qRqr?uIF|M3!QP2Z$JnQ洹'e(s(FIN1c鵁g)xھ:|Ax:O-5-֯wi JݷroT4❮yrj)EI5j2rM2qMEmJIJ_ oN^a)j6!F(g]&+GM//[ߴ$ #p񴶾}WBI`c\% 8؊4QrUG99~5*x3j(JN! #X%5:zlEW ʒ*xt IFxJn,(T' _hcCnc^kVJ7\M爢ŵfG$ro^\RPC CԹgEz)Rjt1/URЩQœ%JhCNx$$VZqK4{7:*:nJ^LTYNh2?y`Cg[~_qW|y_ rk>^ɦCjtӵ3Uc(]?M|%[?=UgfᏉxGY-Z\BVkwlotFOMԬוֹ'nћ ?i*ZRVNqn3Jp)ٷJ:*(֥RZn~GRUV*QHb%  JSZGO᷍mI7yJuVkAXhv˼dׯך "rRʼhFu%zXi=Vj {VNtZ?EJn(ԭ(X%F&T'V2iӔT**UhVtkOV>޶JTuJuhZq]MЭjQ?eV T<&cM (+:S+ ޽0lD]3AYd5qie[XRysҤZܱ"O$6a%RVЫQF6RNJ7'4iI.v։?ϋß<6q/QK tWHֵHLrj0հ \68ib8GW:>h KRVMFR7(Z\9f$J1Ŀ N ~=,uR F4T7dA;M,PƍR̥8F*N T9iǚ9qyJ9Rv儚mkZ '+PRirA|21xF}gBnɵ[&GSҬBk>Q t5)m.-e}[B]RV|&9S>4#;*N 9:ZBOCFM99EWaԣ9T6MtSܨ٨89GݔMΔ^Y џ /ws_|K_Ӭtk; H4GU(PZH`#湸7qZn%xEڹ:*8dXl,0yt15(IC'JIᣈuPשdPuehTN8hڿVr-ސ ( 7Xiej:彅;HwrCo I"wTb%Iɤz$m[.wI4&j1NR'Id>~kWw{xSėxI]Ιgi ť,$G}QľkS ?b=a,\q{<uԚpHTGeh78'IƧԕ*ѥ"0¬<=pq-hO ](E(ǚ9}!HjKV@>5n߁V'_C;/ }wx x<#w"˨JJOuѥխo ZvL^ԱӗjB,-x&өJn<ӣ*\'5Z0'`rRIB2KtөN3Vc;7/NW|AdR"𯌴^;X+)EƢH`,D¢g;B\nv~YN+ٹ+B8֩BQq:)>f8MÝIM7QӚ)OxE_?PԵ=?FյR:UɴWlx-I[kwUR]jtR):ЌZ8hyFaN*BW(SUJJ)UehiW*OkP ( (( ( ( ޟ?RU /GMC⶟JimCg x}ĺ)>,h6Ocj׌u jN΋%8`*kS)eG^1˳LU8Jt:t|KK ' Bjז̩|?,K1yIxԡ,&``+{as¬>"6NuV:/1ߋmgƿK"5_t#z~8̖nG h}viqO Pf4F4 RJbEF Daq$&x_Lv5.y#ƙ=O?[;:Ϣ>?>(xΡOZMub7k͇>ǫDž77^4o-9|—  U..uGp,&'Ru,:K(qRSGK78,=Y&yWҜ)ԣWaWr8s (8b^#,uፚ_I?i~4A|>^&qF]7ŝ.mBlj dqk$!4.| 8s8Ѧ_ѥƕwnNi40l2|I)խ QxEIV:JجMY{1ө^u!jqc~|oo ~~y o_X=%-ΧxX4=5.#v|_?^6U JR:wmZzՇY%Y)2u F,:o+7*`mJ:2GU:J_X:{_{q1!d|B8Ŗr8Na"&(Ο+Earע}P@:.~? OLJ-5 xOG5GFk9K* ';yu .[1E}o ;IŜ9gB4p43JםH'WS+iԋ08MISN|W?qO &aOVUp,oBN*՞#ThrS ]YqZ[/jo=Kix[_ˋH%|Ml5偙u=} A={Bb>,pXܕ*5ͧߖL8 uRPeetУUEN'/ F[9iY yR\U,4.db Y'S Q:m;t_NcE6^!&.@/oJ5}>wڵI+Wm8, Y[긬 EQ~iД75:iV5Zp~JL51ХBb̿8>\f/rLMµYb*U`?g^+u'|Jо+g#-3%S$~xꈷV:_VHwwYH%YζoS+ϙӭØj:kZԸifu*jbSF")u\759|ELO}b|S9$juxQjm )GݿR xoO`~FfoM ij_ uhv_އv]q\n"I+hG ҧF~'rl<)1*fSia<-:TcN8(3,x J[f-uəbqVv֥Jw9c+T.cVx\5Š꺅=}KPl2O!y&gIdvwoq5gVj|(sLUESSyF MF5,m|C:q8+F8AF ٟUkS;+朥99Nep%yTu')NrnU$93 ?C (? ౟ #{w|>IHxZZ<Xﯼ5kSҴ[RGynn34||6^Xz<:*T0fTTFIrB˗G~X;>Us Yn?q8x<<1xMwu1իu:NU'jsN\ƇT_?_c?_~w^i|g k+6V1^|"kt4%1?$wOxp?e{CaKZ>#J'Rj()ͥ+(juۻ㗇~7|Sgx|eqod&g'dI>T9elcʫقl!C >SJ|Ez0ThTt WU5JN8w_ma̵8e},a\a*St9jVjp׌\oc*7G᧍Cv ={R!W WHZ#tw5]%,a3 S%K,u*O :O R֕^\cV# [s^U>XfIV[A8ANcEƭ b0O.qbsmulP@p2c,$~SjkM/ >'G/4I5 ҮuŁi~dz ZU\.'*P:!UUaF*VT:pr/.3iBaSON3GJQ XS zpV4*pJ2JRGOmQ D1ZE 08$qF@_'o.ݿ5n?[vߛ}"1Sӧ.BT!G:uB1ccd?cOՏ[M+5 KJ^!ԼحB2;T{M|W,:a,p\5)N9e29TN*V*t Τ}NJ'D=haXp.4Z#SJ -N둦ixϝ C>m(ළGCio'ƿ5u-Wnu?x\ѵSžҚ{F <^Oa`e8t3<,p3Q®xG)҅JN ,<*ARRq|>7hjpSdyB8le+0ЩR(PgҡRj0AK?Ŀ~͚xo_uO Eb |#5\i6r 5#[ԬmYΓ\63s牥5Ƣ _ |6ɭϩ^m^]#NDӓ;x+EBx:ppإgG18X&XJܾxyb*WKx 3ɱTY~%縌5L SCV<F cC^JSxRc7*|-eXApxpƜ:5fVXjubSºVQF>UbS邀 (iM4WM=i[q5Wᶧ_ տj\jxwͩO%֑$_؛d ${#ʥ œ6 CF J#T(ҍ:qQZE(Z+Ekoe˲/<>+ƹ5lf&,F*l*VNjשVU*ά*'$qO> A|jkSc<_KxGm'#x2E~2\7ȝ|$ פgkiG9y<'%wJ32RU51p^d!bb2jUq"YD 6sɍ̛N27YN~f#)$PH#Ufڪ%1,I{%)p_JMR1ҔIRLet$|ikN1zPMB(N<$;oޛrgֿ'K?x_GM\_.:i;[x .ٍY#~+Ç֯o?c, F7qtb^ o붩Dԥ]Eb+9:x*gq&sK#Rq^ܦd5)Ǝs)REcC'UjcO|mit GZd3LEZer<%,0 #lWl]n_mͳM^Di_#J䋔c7ʜҲrz|n&| pYW-ƬHp9pF5Je{a@Pxgiߎxƚυo -Iu).Ct˭$kl[=20O<|oը:t pY"c(1IE$IXH< /O>!VC𗃴[^.2VAK˛ mcevKs w*@y~"S~2o'?jI+⫛oj+ӈd X͕'/e!s9FY381c^X&<;|,:GC9Š33y5F,E_n6ΪpOp\ӎ2 eX uYeZ] N8AL)b1pjaG  /O>!VC𗃴[^.2VAK˛ mcevKsԣ_%ͶC;kJTF毚ˡ %(hGƍ(Ɲ(F 0VrӚONf~'nO唼?ynWe^ dOa9K~•;tܿ ߖ.?U'C]w&Yw)]ppTaǞՕzJ %:jU)9җ%X*ps+>ZN𕝤(%tfuG~K W~%~Z]޳? R_ACwρK]v Yjމu۝24_ҕxLnU5kcib64(P*apL6^x|j Sb1^?o:_>MٯgY48S1 0UqeL4=fG4 m\ PюuUO? w!Lx×~ #[|7ޠEχ]j]mO(-/ Hq߾q9L$1ǂŬ-7K ({Q̥ZJVJ2*i|߇xl^kŜsK IxaS8}Y֡MΜэZuҭ^.)a[OZ;{-xn< NGe/doi;MwIu(/8'pX$UfUpU9Ô*UxxrF9.8Xb+̖_8]lFY™MJ3n$R+0ȞAqu91ur<ң^qU)׏DtXe?D"p3J (Sǚ^aynRlH( _ 8񏉾~.EN",B.RL>R[D<3yy&{V'S*ICpNqqPmkI:[B(|R/ #N\ЌF(J0 0A j#HEpd.JNRx͹I&X3B}Z0aZRJ򊔝Mv= Cs_}{H/ROX\z FkkSS7 b,gGH&7&oc,BqE= tV\}|Yt)B:icTdT*TsLCG(g>UVHRKK:T'R8au(95`|cctk/ٻ_$3~OQ5?jjn|; q}bw0KBU*Y}:𧉝57|L"+FTst8B4^"PF2R:ORx:5yeQo jMMxTDҦVJu\@P-KMӵ:G4-[IlSKԭ ӵ-: -ol/nYmn" $)xݕpH!8FIetדV.JjB*VRJr*S qjPd($i?~>x ?߰xK;XxfҼ:sJW]>cYhV6g!"rFI)KhR rn1 MN]E'=#TS|QJS?mNV۵?fxGA}K:- |1񎣡Ɖws!嵒1bwA^Vu&ӔV..' }Z8էK)ӒwC*^:IRx_*#NpzFlJ:;SN>kYN|*Ӭ=~2gյ7-Ҵm.X[xٹ9S/\06PS[SX ,cq5RnPSq5:Vc^IJs8{:7&уSM3~ɞ<+PGk|<}ƻDд%Agҵ, v/h|S9")Mkeqϝpz/Ɵ`T'SWGZ|7 7ʰnϲ6RSԧUuڔ9b3¼"IUQv:P9;h~3|_~|RH|Sn?/ iׁ~%{x~oj鬍:{jwkdўCՍ8eXjP1<9b1#Bv7Sflce9#ͭ7αXʎpeXT<hPW:X8*xl5iZe9D*KJ+ C87B,>O ֒*JyNWƚVa#KxZ[$?Y7OѴ #H4*M4>+; ?O;k++H 8-DcHUEQZUVZTZժNZ$RJr'w)MRnݙRN*t(BpNFWbW}:k3@ =ĺF^6sھQlu-6)bf{[ehؤNTjB"NTR5iM)&U*ӗ Ԣj3pg[H8N->YR҄]Ԭ~;`< ? x3BG%E𞅥xwIW>8+Țvief2+8{*(' vpJ%\pǞR*XV\Z$rs:tF2gbh]s5Rz9H`<#si߆QYcDGFrmMpB+:YuJi+_NpHS\Jsjӥ;qǡF/FFpѯ ^8 =\kV6wUa]Mk5,M'I_Q[^xzt3׈to iZ6`~|[QiZ|(t)feKwi17hNH(S)Juj8ӝ\F+1ԯV9Ԝ=RrtߩUu&ϏT?_)<>6ÎiV>#WQ-l+OEOI Zi'JeOoJ~2po8IVf8smFsJRZi҄3<;;_ 4~ x>8ῃoPŜ寇7'N+}S_|":kw tBHV <.[3&GթV',f*/XW_Zu#:ԡS)`0Ȩep_9}*0jr| J4)C_$UUo|g&(|S|W{ݟtD]-Aw wZtť50^G3M$*חZTs,F;+yRܫIcԫ8rTRj>XF'%_Y*>XBEY82\TVnsm>yspLO1Y4Ͽ0%Qeǃq?ӬڼS|1mg|_p^u_xO@K}Ζny-&m4ezKמY:ʲ >%ӧ*:՜ VV6yқs'x)NtRM9%w ߒ|l㷋`=mjͷۙί}_rՌagTcrccM%dJ%dV+3ᶻ ^$. k4:ivkMquV:}Rt0Jq)r'tck:JYJBaмYU!T?^("/R!GqS YcGY!43Tg ҌdWVzNJRrRtR9JtS*ۋM­)ΝH39BIŵ/c^j:|;x[Bb[MzF6-2Uw U9Ӝ6INV^˃ܬ۲voV.y!2R劍^N^M%vZuC>Hy5>:C}?Wi5͔/41$W\ؼ, 0HSVkaӒUҖ:𭁆&XʤhEXj,.0R' 0sl]:S.nYf?9{5 gYtlEsuk+Hy{w3v)>U ¿Q*ѡ8BTSS1t+xZj׭Y8kVZI_1N"ksU9}W3gG ЄP ]|_ÿn`h< ^}3~`ѭM{Z啲dqxfyIb<:ά0,֜ԩPF4~*MEd_V92*VmB:tiSBugB!ïvpcKo^?dc_O xo7o:]tm{;oVFbඅ/k_ E,4V29(KK*Q1iק y \j})f5' s9iC_ԗE0/ċYnt/]xRtJz>3z\g`G*<1u܊:X(l}c8 qpXL^aUe>l.{UN*,& .,FӔno٫㷆?jo= ƖU4 ÚKOzLj4{mZ=7RdnY)et2VQ#UEC\5yP)PNsQ#W-7 4aX/GR4N\*N^Rt F'IT?4ex O~1SįmKHӼ-Ȟu}./OIn5mve%/gu8kdRJg<59ZE*\RyfIX "")OQ⪬T/T~ԝI;a0pbjXnF&TcsOiZC.iCOx>(:oOO1 R_qWI;5M .75xOE<f yVSZxY)yh8b 5Z(O:5#\Mj4G5o ~j#խ/_sZ_kHcӤDV^ f0Ga8K_+sW%i*gZc5O ;:4e7Xql QUC:٭<a0֔5xՅ*-ਟ-w㋴,CŮjyׄ qͿ֪yաe(EkƤeRRZg5}(P@>-_Ï|TǢK:kc]̰iUIubK}7JY_\4g<7d}lv!JZN?Xb:8<:Qujs(Ʈ/Vz`0~a`F3mQЌyʥRRpф8MZ8L%*تiK?ot>k~*?%JX>mRoi~5g5:e75 ͷbdlË88\V3+N+ļ2͠,Nʕ:rcO&|Ƭq&#+g~5N*b0 W^)కB'4'FX߼rR8,Gew?y/2c@4 kLּG4΍,e-umquy5Ž9̏`ӡh⥅tR fџ"_6׶&~\%. xU76s2ƹtӖD8KZ'ujzr)~6ROq *FT$R/XrV?.?h?&?׍oSM|qCqk{g5~;=!n^j֜?PkRX5* Bu+õFcK(+BY4&~7|-? g> hk>,c(Uҵ06UR7}e(Ph5!W 5SBN ˨bpiӧW ^L5JSQ9Rpc(1&ZN|$Ux>NqthF&Vp.*5]UuڕnjVAecV/0SPYӭBSR=_n?5>;e_7>;s5SǥX<>7tɠ|%o ym֡yq>qjWx[Id񩊝JuiQq]%kƤQ t0Y~_K+phJo~y|8γ71ͱ*,X|#9G+r{:?Hʮ')s<jT:_2""V:7uu_~ogM:t֛-h 5yଓnU Ng*94!t,m⨬GU\FS\lEHYN5zٗөa%,Fs;sxL״]G\f]ž+|/got"+IuF~i*~SqTNcFׅpJ1م:iӡB.pFi^ifWauj`U(НZI*ф~[RJ؊i֯RuRrb( uK!i5Y ??&?Xd*P8&w#⏊|h:7O/7{uCz٧GiE^"O+ RҡUqLFaCC'x:*UСGUl=U*XN4!,+u l|oO_#Ng`&M𗁼5XiWZƱ\^LoAV<)Y'M֋<Ƽ#xˎV_:?V<] ?Gx Oz/\֮m}!꓎arpMw:ca%ZqXɺx<3TR 5yUQNpRW+1apgV#ԍISW:~֤iU)s48Jt |_ߏ;_|#V&%7u/ZW WWfܸڍZU|>_F:[Oۯǯ~ӿ,1OUϊk>fOME[$\4< O=en-~pCcp1uJyWP1L.;4a]T0D0.tAΝImkԏpr6+/q7"QJxzU~ձZR֥(PWURĪSh ?˪RΫ/k u^u NqU(`lv]}_`ibTW|ZΎ_JeW׈?iO'^*yxU3x'&-ocipݍu?8B!jDlXJSrN;Us Y^'ՃjXUW@( n12C_1%Ϗɼ[pr_$pII'},FSB.ScRbmdvi&I6۲KV%նyT>\; xß|1I> "|T\KGZմ1sSD:H&חg\ _ײ6_iUԧR6Mak:/(:|N6f~+jpX&"8RJx|]:RzwNt*(]iݨg¯߄V"~+) MI㶻{]CHנ{x)Ҭ4-OVu//iڥܖ q?pV?8 n MfXc09SRZc`0ZStfiʴhҭ{ cg<7|;.{uj~ki}_/_fu*`s |.)J eTae~` ouxo-w\{\ߴo» |S +F𯅴(,/ n4]6Ֆ=ܳc*c2~ٵd٦+O1J7Ŭ&'[SP<:8Ԟ97 a̱%C\EүbPx\*RzY~S{ 6|U_g^XYT?"Ǎ>'EWΛz][ᆷƚn/b]Yqe[WM2IEM:)a18_apNa;ӭÓ>$UrZ=R*xkb%ĕ0?2ˋkⱘf8xO+5%FXJԩUӧMa&j^ja,,J߂ (>$g9W!Qc?{.'_I?2RkIbʿͿc2ƴI_{_j>c?gK ,=GIѡ UfR)PBe 6*qU O4kKO tTc*ՔV2!FԫFuF!moSטpx.E1άdV;>̳96_/:<S^G5JRp *qe.hqԲ9E^=<Yg,ढj+m{jQZFķ>_xܷ~-x.W֚)tڋܛ?vb}F{ TN4aJ4TN81i+AFJͥsrfJs὜՝/cc:֗.YTJ\2H( ?%<]kuE%Fod>/$Qe\?aMŽwskkk 776I4#,qCjK,+3PJ pJ!sB*+F1MM-]8BU%B2%B S]Rm$n%}$=3Pa㑦j~ =.Wq-Z{ Q=Jeq^v{JqˡZeN,VWJӄ^aqXTb/(sRwMG&beW fX['1UQVnOFOFM8y,0=~#᭧_ &J7oڞ#V:өdZopudaЩoih.fԍpu0ykSQRR.1Ui*Vc~r^Wlm7Û_ h~+cLƱ=LZ|?Ck-#u >3ӫRt'R:NBU$NIFi:(%J3=RƬr)SiFr]G*Ji+*}m ?$?|Ky'+^꣇q^?ogOutMahT+E]=NܖƎp\L1de%iқ&54_KK{Zp#ǖwk[놶~s. cLSE*Xݾ;jxXNM(Mk>W咺~B jS O밺祘b#R7MTԬNt+Ѫ#t?<)c+[Yxւ'M}& OroZq*JN7xLDmR/ڟI;M-d=|}u≡R[v?]XuvNHXZ[Ddj[)Iɗc[ޑ>kX߭Ik\e͊<ƕ7&WVYV0޹G=e93[P=7C%|_I%JL]HJ8ea\thc3*jZtP\4Bl6]8K1?mW3jC,'쾧ç^,v"=z:?㞣 ntKs`ԵJ[Ɠ:>nE7qU0j8xKq!No I2!uB#EUxRZ(&r!dރknJJҖt9A:$'%88%8FJ2JqF@P䅇+ZnD5|\u_0kq~όcRԴNBJtKCS5+,t:kKKX#y.n%!GWTRTJZN6IFݕ&JW*9՜i҄TQ)s1o)7%w?ca/ڟsBƉ/-Ok~*|COchW@DҠKy2N 05Np,+h47K*O:oeN ܣ&E>xR9iIj9n*Xz>U^)P&9F]c~?Ɵw|8l%A"G}sVä:Օg;%oX7VW5MiZzlGd Z2MIfiҞqӳJt hJ2W_G-k Kiz xĭVCK Oi^.\Cz*Z],oo(e{ r*0p)+F.6UE%ޝOfmiuAbtey6.xG*0fݸ\ <.t\},¿jJJ53*qKi{zҌ(VV(UCqe bq):xt]JJ4V̡RN3_cN9BGn!xGP𭟎wk)Wſ Jut]6(#g{JI'M1)ciҧn;꺒:5+EЯAѫ*k~ʲ~Τkѡ8J2Fx&' OO p7 >x5:\=ez¤R?s /}=j!ugxQ3hM>-]c[Э^};C5ViWnmW_[-k)'T1X*F>JxJX9NSK `1Tk%RQΜ1j:0[5?xſhX7Ǥٯteax?Oy澳5+; Cε\fmQUs,]HRte 4tKJxz{ -)x|[G `x;O=3?ϨP 8LVY~0IUoRƮa=zP@(ßžg|D_KK8hzK2iiY5 ;[{fceicθobp8]|m9eqhV RV:+֤0y]*uPwU{Y;3 ؼ>Y0LJTqN_ ,4*)JRC R3^Q+'w?t5Of?; '_xSCyo9=~?h >xc4/ 𮯤(Ӵ/D$[i#xyG-!OV8%qNiO8Z8u STi:YjU8YS Btl>t_eOuq #pf"XeU, aө'eYajZ؊X ^"uUUaa?fo?w _ GTTh[T55[9mn,e(Q:|#_WGG RgYB/YJ^l.Ji֖"gOWFQx^2wa+sYbc'Z=Z'Woa<&"PЕ/aN$~g %׊<9_[-%YH𖛬67,/?-N]:SԮ.Ly/0aC0c 8XjXyt)B* NJae̦8SxK0e,87JƧ 4ΥIRR9ONx}3|Go e gIҴ}7@w+~sشR:[,W:|VsYWJrhR־KNJ# a νjR:(VJ?>x2%-:NQBjR5(ҫE8L Q#|f-|+Ss=ǁx!1pz|+׶pCmc:Km&[>^<;ԯY},ӭa{/gON5C Qap\62+ C_ 2 &M8`U1rZم XG^r<& c[ΕZ5Z<%\4X?kkk+k{;;xm-- $(-V(a$X5TQ(~JjNYΥZJ''9ԩ79R9IJMݶ۽ѣKN ѡF#N4N*qiӧB\QVIP@?n{^z?炭<}JKhB|5iV"Lѧn]JM[eϹy~n|3B|&*g'*,T_ 9TSu#:TЂ?{_. qGg9'K-QFPIeޤiu#MbqUI.c韃?>Yj?~5|^R].;I>2x(!Z=/ ]7SkjMed"CBTjU/%V j0CRt%VUqRXʜ)z&E,gykBTp(PX\T0pʳԥRkFjF*R$W?:">"b5Z%բ֩*ShН ѭNUF2nx%|-<^+:ʚ7GNX>*EMѩ0QGo1+H]Qk%nO qxHws jΫ &[YM 0*؉eԖ+UFY}*}b*ThTZ)ajQtj Bry>>c)bc39(~5c.*YVb1XKJRx[%/>4x|Bд? ^9ӭρY#V~]\>ӭN1 '|q6u|1?jū)?b>Biuk+%jijw6:՜58I)au< W*wNpXxJtV 5J tʢTgK>`f;.+sJgWu+Uuq1YuyW1>){u:U7 O;iwjQ9 bhFQquKV; R/_M7g)tSi7<:xc_qhd5j6vyZme \ifUU󌶞uZ70cY8L\RYg=+⠡^IP;>߀/x/5-m&C4M:3%!qH74O!y%iGTYsIA{aN(ҥN#N4iB(҄)PF:4(4Nn]08\- ҍ=9BչT)խVWZs9֭Rug9Ϣ;B (ίM|pcwWx=xv2FeN]Gq[Va) 6]jD5ٽb/Eb0ٶw2R 09QўB1aB/(xysp yM,^YUta〔SV`a*ӎ!j?w =GDgٿK oL;8mL4 xZ/%kkBkk"ps׫W1_"pQJT԰B J4BP^R){FUS*H83^uEBY|6"tieJt0YIZZy˿O2+|Q,upxZNJmYDt?oQ>uMbq*V1FˆMQl>IZL6&*51_ ON*U,aF̣;%!:[&)bZ(PpiS 0WI*b+8*ju(s_ &|,+*SM}"wVGu ǦȷF:l6wp[K JE<ޟpZQ{uSVsR#u#R5'VVfEXcʧlFTJkMӥ BNzJSk)p/:|5||>׵;/*MGSwaC}1X̗6>-ܷ6]̽epXn# NZ4pxʔaڧJ *U)֍i:ҕ)}g~??˸b|XNxL294%Rrt!*gJ* >+9_E%|KW#j^&◆{$?u->Biϧ|.-mdJ !Jq8sOV b!:5h5J*k*t'BkS(Q?WpNq~Ja)TTQ{y*8N&OO̾#¿?޵_4N_I'q<0Hf갲j)-ŞIi ]IbU^Teҫ)RFJ5–F`` )ʌ'+f8!xV.33\~R'3Y2꒯O Ejn)t5)}^@Ph-yIG߄vt:?/7aՖJ7DŽQŦW*T)Qq<5|kbecSB**|&/kPt1u0t".'Kj_zόm=v[:Վɪ4j>YY@sJz麼V\+NyqU*¶ qXzҧci,M7NSiʭ(U/oxS,<9>m<]<,1)w(XYQrGOէjQJZ@Q=u秭zݶnXB1UVJ.?;~)77M 뗚 o77:zP(>4x/-~q%btԼk8^^ ѡ6RG1/B:$ႍ)BqoI5UiN_ld1q;0|^ɫb5žP3#BZQ ͉qo< -+7[,]#x օ}Q./..4 W-eck,Z=]ur%uNs*P*QU+8+*):6S:t7yEԔ?p52,p3 ~f:Xxj.og)jr6ڧOGrqP~O:W5|/^k,-QCxj$ⰼėMRz&KW xiC jFuuB1@]˹ܸ ܤr229YՃJ5R'Rj5iS(4$qiZN/JVROW啝gg&(¾/J~~*7/LM߃ug|5 /}N?NmFO3;} xn1%4h^RXG]/w *sjЭIR*RR3eo >Bmq6-a1`iv, iN=8l*uc*T}w)!irUN 쯇 |Gn bRk⦵j&[ ONeѠLJ<#k VMn_%_J^5`(c>3e\]t^uOjŽ%J*4$u_mUbb`{t!NptBXjم '7mR OjPƚ!֧ Η K,y7 c1qsʩ~OW=LTx U*XX<%:XxO(tCvlMJ4\'*xz4K apgN7W[gZ,3~*ujU:a*՚<]|DQ=+?I2xb '/ _jAxo]լ,.'k>&1-ѸΛ QO7+10ⰸ.*t1q^ÝbTU!FT,F&HԍE5lnaaU*&8xz8x{VaQJƴ:P*l4W5?f/ 2KS_j_xz{Su=/v7yjM̳zrsknm,Wѥ0գGJ{iOjВYBh)Rq{+l7Qu'c*^ßBX''KFtҠOp (7|/,5h W i!-xC_w-ai񽓽8wg穆iVҝZ5R<,^Ei}b5&':5iҥJ)M觉EQ*kPR ιox>ox?R6^Z_jz,toVҵ<nbIQOxj50,jPJ5zXQNz\ܵ(VU+®qxyJ5%9pPSMڝ{g'X׼+ x*U'5健?w_~ߚuЬ0+S(gQԭb*1UtZqRP#\EXb10}YP@+6t=/ot׾MGM(uHVYโ+R{Y&'HH%@֦ѫIUEէREVV*AT=7(N*I9BIrQVUӧYR e)Q%/gV1dܳQdRMϿ8x{?hZS,4E᭬:jH)ioߴ VTP~VR*.i-J9+׏iѵzٯmQJ+?P=*ڝ%QWtKBuYKj(}k O/h(?:mߌu-#Ŗ׶7j[=54w8yxӆ3iI{>OiE%WVxWn|ZhJ*PNpSRZ]j:Q+U[8;XjavTɺ2)7*G٬58Qn/ UUXG$0¢ [[ha(i%X8l54L%G N8)S*uЅ*K C ObqU1\V*Օi98Ҧ7NzΥj\M|F"?>"xGşi>|k;>#4Yl*3ں0)]ZxZ)S?eF4! F /J8Lqҧ*QSNXք^r歍z1|;4o[xNm{~,Ʈ!z5λ$?m$!Y[[oywwru҆_Og tRNҧnJQ~ʕ>ic(ή&7VXUm%RJ87aAFi9$ڌyJ:t0ebXP@?ٞ~4|vOu_ km x{º_캼Z}R麤IA_isؼfգ:FY^*}(Y**\Ahה#MFMҴo(JͶ_s~Shv@~ X|3o-xIG}:UtF%0iŕt;,֪J5#Z09aԮ*xR Stf T <4J#jnht9Z5(Zd_4e/e)N794T~`\-?-t}bú5˯hcUJon!ct%6oR(S 18;+ W R8ZqSEʣI`R.eTMFu\d(zů43LgH./4/jzwVjwׅLgkV 2!:\#7VbU|gFJcUZ^ƔV 0YJ3rNT*RҪ!Z>[isĭ;)>mEQ5+[=^YaDM WN R5(XQpTNtRRBiA×O518Ԩxs[_>wVJMMԩNziJjUVi'R|c#>jwvkz4I"vMHNH"(-O]GPU˭ib%r:RV%(r\уIPt좯N_~U7̥W7^KE/=so|[~$sž&|ykr^?oӾԑigg Օ,|4qRpXkژZkj'V# F!4ԩ:4JJZ*&9}j2U$VZmRT+N\j_O~ t^ލs%ol-jZ.5otj:Q+U[8;XjavTɺ2)7*G٬58Qn' UUXG0B [[ha(i%8J J> EPhӌ(2SQF*!KJ40zФlN*Zf2bIέY^N0R*nstԭ^U&/j?ǯKx x~E޳8Oi%ǀgIL(e v~iԡ8`NiN2,VH(B?Y7N#MJ9sVUUw%و:Tc4#$RŸʥHaNUVr'؅Wg۟=f59uė-'@k!|tmvz}yno.Z0JTX*~ •$#:F1USTkF(qBU8jb1ɩq5RR(A7wTVRZZ_z (;펻㷂|+pc]?oxk%e<3M"Mb :L7>~NnեZ4T7N)GHԥTVnjF*j4hfhԤxEJVmrcrC7ƿSg់|em[Mb;ﴹҬ 6/!O,??ӧg>RQц!O Nu)U”J58hRU}):TStFPsѯ.IBc%$){.IJtɥ8s_Ÿ^ u[L:NYPJZkw.>%:,u  uc9\V]q4J4WG-R-SF4iiTVqqCb?J'vRT14io8S9VN1Is:s*Jw}*?ij%E^jɧ>sOmiewƦgUVFBrģzϕ%&*o)Bp Χ*ʜR`krޤ\SJ)Õ7gw\ 0Hi>v' q\x+zY\#ykcki][{/B*pTR0RF4NUxV5.Ypt֖*/k:SHF5RZV+TԌg̥)%*ru'G0yMlgXEų"@dFA4 ",\`.^](/K÷I[x_]JKPR(:\'1 oeRT8^J&xj_~xKCд}ZIqi:t irYGn&:dG,4>d2"Mj'QSK{:IƜ[ߒ-˕7wʟ,oh(F1ppPK7iTiϕɸ(rE)KNG)^,(9roxcYݿMٵ{Ciwaa}kѯ5M3YCKˑǕuiQUjRjԜTZ]' Ҭ\ңRq7JU)9:tޝj|TSFtD(iEwhBR #}?h~(k %x?zM?H?$56HƐֿaQ1h +V?ٖ!Pnֿ޹uxh):W9CpοO~0ſy˓}g_U~_u^2] fm_Tojvk6wviKyŢǧUm17ھ8 qR>1}l _ NndRrx˖:`MԄg/^RUVj%G:jSj<7O/^mqWΣEyuw&]3Jҧqt *խc><."'إ' Щ:+*WRN8ҤNln9Ѧ8^Vt*biSNU*M(KsʵyUu10aqujBe 4烩^c[RNH(}(ӆK蟄߳o_o<9׀,5[/xկ|c&n ڛg7!ףծσω^1$}ږh ][mƒT߅h>%FGe<=٦qSyFѧ.|S0\)W̧dq|% 4LV?8Nt`qQdپkaV8aeO4h9qu%yMf)ƍL,cRJx%,DRJR%Q2MIzgy^4?go|;ռw@Qg߇ a9??ߊִo4&chʽ|_sVuO)X|&:HWS2a(S8X4N3*Mb,5Z5pU1S7*, ZX,VK13,u|69ТQ/Z88 ޷C߲w_Xo!icz\zU5ZMkz7ekC\:iyo XoTf?R_x!^+ hch)ڟ,/ӌk}_SX`8pe^x,s'|~]s8եO\&*cRζERXgk(Oe:'+ǺmNĚj)YZT~K eNcrOQTZpU*Ԝe^ _1~?^TΩuxszVy?uUolwXwZ:!|<#٩ T]L2˩P9Vh`pezsZQ^rT*Pʩ%7Z'|g>".$1yU>f.*1*uC,Tu^PRֽC%>x⯌o fiZugW-tm%I Okh& hEŽ3ax(),~*#[c{<6hA;NjZY4gx,*̳γe8:eTOMJT,F&J8L,*UJxaRJU#~2~ܞ mōop?xWJZ `&G KEcf{oZEZ Q.U 1f<&+*>*Ye$GC †J3sEFx|qm}{ yemC"uwR]<ʫ`J'*eroi$om^ojohCkMSVׯ#l<3,֖zXk3+u&mk9X<>*Pxf*BNq̰xLGBwU(Np {`x&ۛG'+F51+SǬ_iԝ*X GԾ/m+K|[,גWZ$ޖjV[{7RIn!Rҵ {2-n>i10{'NӍJuLfT<~7j(Մq\EʝXB5>JԌ.u_Wuxsz_Lo6q|_;&%1M:biJT``q3b*4Z*U |f'[|Q2~cqW 5!Hel5,N+1x.0US%*WCf~.|g2Ysߏ? ct' Vm&x[}3H/_AVf]+QKMONҺ:BbgpUj:r`*΅zvjt1yPK#:WVu͔"c3?ie18z,_ S ҫJPBu84+'길Kx5!DkmgO[?"VGh>&SSQεX4dcow0#l,QO)0x:XUX,! Zu]L^*4q}yN;tq87F8 5Jeai4tBJ*us;\GoVd-*uL6bq5KQ`}98Jb}z49^_pWy!@Pb=V?~(^km?I?P\Y-/#DͽٻT_&O]/B5ϳi9D6px|f?cYMdžsX 3qzP*_U1jucN8fnRQ(| n#*+52oMxVƺcG)էW/W REuIb+^ƿ%ك7|kP|E~';'/|@U*cZѴ[4-DeX3b2:yL0g7ciR]өJRxzV)x:7XSR%Zu*C#(Q*SW<4iO)R*Ǟ~zmΥ3=XYW{yxOo/.o'PZE%( GRb8[f :F"Z40i*kVӧN8.i՜ry||Ki8C.#Y_gwlʣ.k>(ŧ<#JxoD'/}ᦧj8~"xf-oFм/^j#|2?+MtΗ{if7 V'):aZve*XPZ1rW  KکFqt5֣eg^#5XR 8*T40)NxVNV?h6R,+CSԼuka77(lm#)TFu_Э3 ҝ|F#Zz4ӕJTӧJ4PUܹR_Oq8{U;dU,^s^ h_l0x%?^ULj7g G|3%ڥ25նjiJv]Ikc\jԧRn,fCJ*/1ZsC' E4 (,\ݓvV.@?-:H5Okpc?~v|e: YZm7Q_ep.芭:\X7a\A¹2btBhcX  ҩJyeB\C QNU~q\}[p8Fs\[fTQ]}nq جVb'BxL,pU(b:RpRk€?:'_M>#b?O7_ xğ|sĚׅ<-~m[uILoFu uO-. Ks laJl66TRK/f4*ʮ'R"1T.*|s-^XxQpK^j{O0YXƱéiw:vCqt^8)aUO_kN_'^tk˱ԧ<6'V>ꘜld[BqpXɩc5V V8W*0*xyccyςGRx@Y|Lgik>'<yŶsO{Bl5M3:^݌֑{o,5͕ھq `'KU^paUjlF&i a0U(WV5(NxZ0[x;9bqV'ZΌ?PS` J6|60ҫ+J}ue~rJZ/Sq2Y^w< rLb:Ї2VPzkWYǁtе4ƭx7ï4;K G<m/I}cPƛ&-. sZ{=#L0]ܛk+;O0eͳGx<4,=a4?uCCb*ң^B4d)3 d<\+VRr ^efu/pJ4^#?iUZQa5 Ԅ(UGX~ϞƯ |IKo/* |:nu#>֏;= Knh$m,ק,uzWR 'C-PXJت(FU1]8 .X<;ejB& /R"YU1O'υ?|]C&k xSς?<m/ ٍWVH96ڶ Z/Uksw{S4fX|bs^#0K*Fr517+,]F" XNiҔj:1S`s Еln3YE<X,12Uם7O C5iW$~?>+jğ t&oía_YF2WjƥbvP73 ky sL-c M=Ģ$g1 妙%r2Hq_֬jt_URС εiҥRn0EӇ |ЃzPgni+RzEjg(\h_ X|mx!aڏϟY4no xZ=RO_nm,vjNF_U8J'/ͳ rԆ-_IӥR өW*u|OsVW,-!Ͱ%``4TSxjys{ZxWazOf 1TbNdO'TT TU% t*''h'F)$4MIn%}/Oy;Q|r? |Qw).x:?|kAn6z xGXnA5fg4aԭfmR/b֧VWWկO)a/[ cZkƬ> Ř9ϲ~[fJn%P[ ˰)WbV4ZLD)UyoR}'3tں&x#Pcgğ]u]6Vֶ0v_hz iƛyjЖS=,7qOG9*9ӥZhաR+Ҝ aPӕzn1ycd9],x_ `V&7͆UWE(Ttq4]:I>ғ[ Jpd/~-> [O >#7< x[Ě/%|[\izeãXbsaqel 2_UWFmG ><><6[SSW:GsxJ6cS>l(3\<>jRWʰt0q8^/EyB=:oN^-Hoŏ/M+Z4; px.vx;InTO;&kkRK3fLuxЫ<9˫3bҎ"TqX|F&JJj0<#9W*g؞rynuK,wļnY5 ӥ6PhbgugUZS¥Uiczhƿ†-thW*y\a?v+ exe٦/ Ta*aB5nSVxTᰘbpg=i-6xKKkK^Gswu>4w+hzXǨ>Cm^ItF+aVgfU'O ԣ%Ny(URZX\. F/KQpsSG<0φrKK*sVR8nq<(Ҟ#5B*Φ& +㿃>x'G2C/ (ig/ώ/|=C<tl:S>!4>Ѿ4ڥk:hW|h5 qjUykua9z3G *tƬ*S)W:iR3ңem\e8R,TjSׄp,5\Jļ<ԣFUd+;|;٭5?GI4=*t_Xnn&in&gUye _Peg%*̣'*\uHSxBӜb)4Oϋx~{<$p?Yf!g_Rx%*Ν/iQԚ|Ҍ!iXw?ßV:e&.on.]{O^PP].|Q= =X~xy&q>y~EԪm43/я*kV&g e|&{q˸˅;N|^k^\U' <12-J̱O KQ֦ʸod?'{#JSKD}_@𽖥i^֤EM)ukTJB8ʥ|EUMFUk֕:48~yxs M5F_4ɼ;HмW^Ynlt۝G—V\xS9%·ywd\7β%̔kխW0V)Ύu`jV8:PK=G"Ͱb[p",%E,MI5NqJWORa{Xi֗7REmgg \JFHcy©<⹱>_u= JuT䂔N,#)J֊miJJiQjB8.j$VWn˭ڏ~0/37:u ZO߉&Ҿ%xDG}Kˢ[k&nt;.-|q  S^&,6kV[ K.ҧV8Jx1*qe<_ʹ,6SWc8&Ыx>Y^ R5j-|D^Ub(a}KAU/%~ 0]xTesl[Ac泲Io,tN>+xm/o}<>wbxjdUI%L Ҕw,.3 M E+SX8qe|+UsOuBRlVJxSq*Bi΅l5U.z."7hN񟏿eu *?xc^Q_x{Ԣ枭;}W[\ky,<=̳NW Qx?*:52%Z0hU_[ʪ֧U+f1, <.<y`pb<8l&'S+ ~|5/eڏ_7uOiox3W ^gּ =+ p :# ?Ceb& kFq\*y|*MҭGF4_ ^jtlDRjRbjBZ0=n|B<&# ,&:0Nq?k (/#,B5J|)? x2>i}{t!~Z0L]NcZx4[5*\aqVCb'RսTM \)M*N*st#)Ќ6aEuԇ'cQ75 i^.RNdߍ?&Լet%Ѽ[xzRy D7PWF >ں~Yye\eH<Ҵ!:I7/>ooڏ,i旳Q(MFrc9SRunx/ΑmoG-O]M>OQgm-^!|?ᅘ܉`[ԭk{{-05\Ox SQ8of!礥Ia*BhB3uakiH3*|J׊Ur%9J59B43b/ړS^ /+_vjwIto ֓7 u"umپΒG[ԭx|SHήaR(f8aI)N> sR-k#M/DPQօkq3xo&=YnuZ,mn[ >]F*}~)G{cNBt;T5Ԩ5 (9?Yuxİh[&o ^/U/-=#Ú|V1gNu)YURkTOSJjOҪCFnOk(xG4IfScKK7/哧*>hvaREIkG4McĞ -]j'KPGoiic8qVmS9rU&4JZv:T*'(ӧNQ 515aǞzJ7yTSc)F)k&l7M~w/,:mo +-{+CA-xs‚Lz&k'rl[퉥Xpx:n~ҾbUj>\qi>Q[8v 7zuջYi_i]PB6.'./N{kT5(U#)R:Z+82U>iJ3Q9Nu!))PE:_?ƺ7?Û4_|q{D&h#]xszOMcZ}vK .4 kJrc PW cqT(n)I I7RT-ʝ,Zˠb}6|>lMY5фi¥ח{k^lZ>ּ!}槡jZu-3ENY^<Ɠ$p? j҆2=i*s:3BүBrVT)'9r;ԕ*pnQҭBՊ s\&"*~4U__@P@P( ( (ۏa\wxh_ gZUv(C|B}? Yd[}M-txRidNLG"+Ȱ٥J2$cB 5*ή&Ȳ88h`W ``"Yu_ܖ<Ljq,%L~/ `|R{lkĞ*k{<;ෆ<) SWe_&YOV/'Ne7 flÇ807 (<>OU9WG," V^_xU\Ex\2C)S 'n(ȰR^Ҭe %qsU3LK6 ( (ɯ#??)W@PG_LP~Zį^}&>7ď7<~7auOC?'rOVNμ菓|i<?o>#|bczˆ;ͦ-fR|i xr]K/8֯V^)E,>ESVoџ o|-φ<+4j54 QOieka"荨]k::&qስ/7iSXn"%8&qc`f9G KSBS`.:X:pϛf59/U_Ŝ^gFGL: cʭ)嵩(|"iᆥ'W1x5a`r^i/n|I?ᖅi%7CgěI[ໝ7⏊u۸Bg_ėj햐eN )ɫ152βc1JJdGaV-gZkRw֟%V >]|@S-h&7ZDž|Chڤb gVkeOhι>p 2quβ: leF*EV*U(ԋ_Iׄr}kINeSqE |,*65]e>2U/ڪQhqO+>?Bk>( ( 'C7Կ|LJBPɸWN޼?'}9f/BwuZ458AQ 8}F3aҩK|\%ӣ_ 0eSg!p1Y+;6.Xnlajd fx;RY oUjqw<0x g߄mK_x'@^,n dwme[뺕 3i,z3$BT ..R9e~_eӞ":T13OB*I(ҧJ!\-xS'm< 5_,f+c E(:eBLtRYԜJRz>( rɱ4g^<ʜ7e6ɲvOؘE\As)~gz*MKG_/㯈1>7uou=դf~ xrD9]Ƨ{X]j c0>KO*ٮ"7Iag_ӯ: [1Ӟ%Sҫ󸜯+sJQk㳼zbeTXa' sYS3.Y~bB15JέV_LM'?N~|K?.bz{m_KOŸ Gi6/'|AZ^F%ߞ^Dx4ړG>9|kC|03'ưh.X5?xkr:wt;oGdk.ySC9qp0L.3r}<~a)pvGTr'BuU xhSèJs2aU⟇?xJվx 7w. k^a/5Kx!xC\ϑw0js^ʆiF t=N4ܧ JTyeLʞ6 g0r}c&JBTsnjr*N~Ҟ =xS5K7>mOT>XZKVj|2Vq'Z=o὞f{|-x.Yz||v~֯+ k;-OkWE5QksRJG5 )f\u%N%85NP眏IS Kq^5*8-I{ =/Ih7M㴱R [;;Xb(a#UE}MZ+թ^RjV4T')RzJMɷoL&`pt)ᰘ:p\5RTѥet0R1KK"ftP@V ~?t^ҍ&+0oG TX~Wڟ|G/?׌><}j+ F=t.n_?"sk#ρ-/}oZ{qp,YhVTϚ++'<52L-<xjsJi9a8L. F._:Xג9)>,Vs*l?1U+`8"3ln)x\N6+ ɰ9v4=W*j??~ |gj/ [hi(oqG vEsM/: kEo%G f43qt khEJ65KEG3B cx>19Ty+|6yS ~✳)wʪb8cVͲk_8[1+Rx}ZWjWfN5=</5%| ( yw?z+?~&|?_DWg^<{ecܨL|5|Q>3+DWƺwoxh6W͟#~"~&&¶opgkI0j^Z/g-qV\#Qe[(О/ %(ckYm(x|f[,zu!xK|AɿxKY(YW,v/<6?,_ xrriY`jҌjlfBFSaI>.||Wd?.4P':[՜wjGK}Tͷtͬb;ÚDU94xGC(aqgomR'bh0VxdR8zfkS(nu  ZE&=G/Z½ST|#o#׼Aa{g}hzVk!dĺ IP-"KMZ aL/Ĭsb(U,0XLE%)eW, 0R _q/ q>`5.\7dy;0JYeelNkNT[NX,]Bu3:uB/mG Is炼?!vo>'ɤi>!5֬Wt:[躧m˧xmfEW$Uhf2nPiTpڥ N/a2$+Jp֧ͪQ{jF?x8<7ex"Snak<4W MG cc C)WK ^|1 xkB<=tS]amnD\n>|V;ASb1xj^iԫJ^5 U9k rQ 09VKe\[e _W¿apaj:҅gR8MՂήP( n1ec'C'K?Ox5" AFA<GPL :8 JҌ+QmJ-Y4iNz#%h=b~#PuVb=߅|Kl/5OKl|Xyz./.-1;\})c0%juECծhsopZq2tr&65*B(ps(9fEhN#Xj^"~?fq䕰8,v &/0T(P\[ كz8>`RBrCG7y?M 73UtV7~,-zmx~]Aol_z8SsLt1s,g ׉ΰїfWF5NdVxi(1\V +ic}Z:RxɆq>S5p"q141Xbj(K0x}u);[ R )R9ڪ1qr|r۷kۧҔSw/gCσlO'Ÿ?]|}x^"z,p.ym{sksm{ jU/,_Y4[9.F% NbS}.iP:SIӕ5N)S>O7L p5 Z'NRĪѯʲ7eISr*p?ZLo\ ]x<xS[Y%o[oQ. /xY[.'F _|EͱZ~晇$^5e<>}KKD-7qxkMʙd;bPX{YƧpu*t[MS,eYJ|Jr| idy>8RYƲxw6"._,&WWjW)T旵qcȥ?|ٱI_P| [\Ií6sѦ=g~nؿY/'/7>'CĚÉuo|"ojr%5?hb)#>Qy(F?xB-8~?q^O-9K=Vz^XlQjN7R fʔNXaR*y7 ֫NKXեK:j1x 5TsFUzUkef+2JƝM)i+XY^~z x/BѼI[ctxĻ˸$O7t? j)W3çS>EFXISK. V`koFe_0UPOўc[ea1C~ /s19.aO%渼Vogqf_Z+a0p`pyvp*8\FaZU V8j/xtR_^iT94:?6hZM{wXKos}}c6&q`s? VKM|F_e"RfYoѢpF6_WVx1*|OFuĔs Obӌ/x3*RSNoUTJq-o#V)8d2{;WdJWQ/$eXVe9fdO>7acE+,rFQ&*m D5<)N+,|Ӎ*9hׂ (?k5oKWA>9W7xoM_>|UɄ?}sg/1h33*?S>^>3 1|0~>i'[A=׼{B\HkQ;o46&iS2f9! 4 :TS 9UfZ 9]Ta1y_rY{OP6O-*s8SG ᫧b+a\+> Rh77:5oR&kMK8 ԒquxXv[}KuQ8f cP]pFOeݹs.7ZtPW^n/Kbq*=$?"̲Wqkb^;3l<̥ӞiY#2%yB5KJU*>/d/?l1|J_c}G⟍Ο>sx[D/xi5x /XOKmE戮K'Wt/viJԳ5//R\gNS[F.:UeRN`r58qǬ"YUͱx^;1QWJt(SBZ؇JpZU1t|eZ3IԧNVhsqk~־G|(G8)o-<]x]JMkFppޙiW~a> ԧ`w5T#W1B0xM*ZPP/V3J&xe:yI ,ٷ2W12GqqT d acJ兣^8 &e` A9ApAmh~FQRReej馬Nj- (?1geo7| oJen4?}?Y+Z[we{o5ݥi5ͭm ż r4N"c0،*+qT*4*.juW*UTPNr2hu'J*ӔRR(N2(&FΟ|/e?_b}/RbӵxS{j~7$ˡhZF+&b9&3v'&-V j43 08XbR'6z[c9ӭX|kԗar̩_,k,7\UcrYG4?n+R\_S_T!K]^!</G$8'u%dE«m p=bh<Ob>+ǭ{ڼEYTCR1e^!"-o^g5g~H' VIcO"8WG9㊽h߈A@P@kͺ/|=q|m~όGÿRM~ß?{I淚Aд$7Υ[sQ*s.[ETj70M7**kJ~,[ ,v&qqF""~>80wg|Wa:^C_Xv&-U5nwa iməOU˲v=(G–"j0Q ] D'F1V*G 8b0~J3, jMN5!{Jib"<ʦJPZVU}XP@P@( ( (~-?M6h<| 'ƯBe⭶=cNVC~%ү-].0xia38dx| j3a,~kW*iϽ_͜$u 5Zs\SV]%^<=gGk,eF5J(d5kcLQpG4SB:tj(Z]GE|N|1]5;Q| he]bo?|eO ~*Դ}fXf[:NxG[+_Xwp-X3a<G_ i>LZ GN8_]do,uj`|eqTN:aӫViӇγ,Tijxj_܏e[@R#eѼgiqS3xgº;g&Ig\:ZwZlڗld nG S˄F:gU֯-%Wt᎝񑢔UhPF~vX!*])F+ùBN5{Fj*4UOk( (ɯ#??)W@PSE)/xHn}Whxڗ'FGՐ^"֣^SVjxjTJ,pjԄ\ tUNJ1":2j_]ׂT<JSrYTjJ{җUX\fj:0X)R*u,rU}I1~h+7Z1o+? Uw3C 6ͯ_'5+cXֳ֍awysbtkd9/8(f8\ T{8JUGVZXxmjЧbaxx:|Q%j~?yQ>gC_:ށ"i~*OזSZޅۿ>஭}c J/E{X?L1bTO OeDڜcpSiܪ l?s|>e2L,] ]t35aiA$׭RJ#M ֭J8>Ju/g+Wmk:.6c'tutk# R׼7Cc}ϯj`Պv W18n)y&#|VtبSTyUㄩ*xF9N!}3j6_-2 ,juqXl f//h 8_.1UUƌ?y{1YJ0%|ExFR#*Qiusk ( M{ľ>'=j:=@Zż 1 .bY1UkСg^*)I:!NNms7PM95𦛵R(:g pM':Pr*rME}uoc?k +uy֖.;hVxEſZM_O}Zޘi5Vc!%(K(aZo8}[>y$0uE LV 5jR%3¹YC0*8%ibƖ)`jK75J/k:npjӕg?AIg?־(t+~ӼXA}wPCj0zb+f>[{i}<=dk񊼞7,=Ч8Q^J)F4 vv8(SSpK>|=srS XBz 1JT멷R8*p!?-<8?g7߳o>7ƕ/[K7,-[u{ ֟K-btJ|p SOγ6)P,4C&{h/)Mf^XU0RP* if\12|w4qmYTcin14Ju! O9}_KWmo}F<3-MQa D 1u%tK).[NkV?O0ja'ڸN&(a910{*0TT ÙEJ! 4%J׌i`ҩxp2sΎ# *nqlOOwJd&o[h{ƳCh4/.Ե'7z~'ž&K{^U!-_Zcw^.32L(W 8Xl>aO4.[S¼WC404X7Beׄ6߆e_RTfcCA`cG*xiF+9Ҍ#?:ؚxG ?OmoM>*|+>+=7SEվ#Ctk\۟V[-ԑq+kK;QI"V=ޑ,pJH{5ujpT.caRc1Э?iZfXYsOTrlFYEPU0Qp5iѭB'P1jpʣV2`p:rJQ[28sk[)S? ( Sw~xVƾ=^xr:M޽ggxoz֏ow.om^\Y-Giwsom;fgC:KT0|AGXl- łx+[Y~$7YWwQ,wk lgX19-J>pR:y3ߖqvI/Ҳ~c0<5 XjN- ޜJ/f$$|EG|E $gîjXQ.afBe bxFs/e8+U} z^ҭ%cR m<&"pNqQPT/'ŹNa a+K!xc*ΌaS K Wʬԍ Ny*uOo_Ƈ\ ~!AxLӴ_w1ϭoM|=w[G :GMGcF4N 1 \h׎rʅZiGQ ' xa*J8ƝIbFT{?35㜓1dYҽ:x熩}JN'ˡ1`N9jץr.2F?xn{?&ϠI=|+wn\N]NKr4+^M5RdsRYqOVtkagJ_ğ/=yx)<5 6; LԼxWP,Tu˛ba{u˪\c2y*/ e=1JzxcSF<6iKbr*ZxR%__If- R\tZ|V6:hm@ e}FMCZG,!P:ʹW %$rlCd(֊nc1 qը90q~4)mQgUIeje_W *| /rUdgj5)C/M}8P@m_>𭌞wyMoL$<^t.5;X_Ȅfˈye¾+ NXE -j-[I9:qZ^YO6#B!ᄣȮ9Fy"0R.d/Fja֭QUZJq1ʆ;x:$#XJʣ:j{j25NrՃW\|,Svx[Jfaj^ޣ=ƃa \;?jrGggt{963,]u,5)T1Us/GZ!ݩa|?,^G!+ESIՋ-}fC|J^;f z̲>5&[X訲,[|7%ӗ'QMOltZ{ ϡG &Fu'!U\քyHCjXl<eĪobTubK_d~P@{b[l> x*ÿfx%ƅiz\Wm$6GT,~/ /5,V<]jO|%*֣[[ӡJ,.&:eNH9F|m?̮*-:'4=oN񿈴GgU.o nCƷP,"`1҅ lA]UTs*Ќ18=;*tqEB%Gb!ey)J2#."¯?e (8>Ү/KBxQ '@x,Sy2MZFZ72+Kznxf^9<'R1աX9)>y|Wda(UףA4%):}6Ҍ}W???% –^(kO ^xIm5 xIѮ.gnl&⻺J|/ZN,5:>&*BuhWYqtӋrQakSr''jg~Yfx,g,V3 NuB|&+)S9RZZ4iՄJ-K~~i* 3]t4giCL:_GH4;_N%:ISJypguA<=)Uat牨N& {(V*JpICn,⼯rqS " +WGhSTRϟty||oM`sA1͚|y'uZw "Ջp !e3:3VpT3׫&Gkkvp-!KZx9ͺ,Lpv_1Rpx,&+^"?թ5 H.IrLf5)סZAѭN=nOf8NQ2 +QZqS/ګ߈⛍0EѴvVZ,<0׆M#:7zNu=#j7Vcw+dxz1q`U14LKjէ^v*Aak֥_ڪPF8|G8m ⽖[qtᄥUGU0Օ xxlM%lFp'|־!zpiK'JmM Ek-]uRWѵ tKm;S.mKpQbI}k_[B9eZ&xcWFIQEB5)bp߈80ij8j8sS.J%0֦+ R"RJ619g9S a?7~ܟFnixW\]3RŌ6wj-a_Yc71Tfq<#bR*sҭbh8F?^7 |h)ץhr KJW 8EJ95ͪ- E\:c X.q UUR֟I\~~(/N>&?n:|JѦK<q5Νu&oŵ8V{j1꿝qԧ'}J֣Ϛc(Ӗ UZJSǛ/[SFqOx֗xyҟf1<R1è˓bhM)P.h`bc*8Ò2pxLʄ#?< A?d?GƏ>i1I~ƾ /|W ۗup֗FH|=:6jFR/mKU3#7 \ bak>j9c̱xzqU*xO?ಟ 5 `k@Ѵ獵ѥx 1ﰋ7^"x: H< FH7"8bHRH׳LT1ٖa xn+NWRa%yn~T.2ZeY6[՜[q[ BH6ڝJr]4;= i[cy"bB,U#4RH쨈 NRqN9FSr&&&I6ڵƓQrQWmI]މ%s\Y[7a9 |K]/ͫiåG=ڌf/#1WFu"îuh*?]yw[,\8vA{z<x7+|UU K Tf -WYbsLCaq.TbJ)9ƎTSrDIFnЭCjAKu)Ui|t߻Nq┦$|o_G6Qo]O"&8}WMDAi%z6=/{=V47 s+)3>sHa^7 ՞;7 uQrRV qfSqsI7d[^Zh<?YxWE#_jVxk$xE]o$gAUq_:s ɪ9AX\ Xaի qV# !Jy׌cY(c *sΪҞ3aJ!Pƌ{9apuOfkO (?mo/~5mSkm/KּA隖sxS\tm>ۍOQ~ 2{{l9CZpڗҍik*1iB 7?4'7 \f*)sW I`y6#JSa)F_>(y{دF%C aFZӬgxx3`+ <50/UEJ?N1ӍFJ|A|[v|0ǟKO]h-4rzPomU֭.lN5nu1ajNv5tWa) aN'S:+J*\ӥ U>׈x*^CV*UxQXQ,N :(ξ>EDVS|_į_⿈hc25I xH?i IA#ψ5յ{;{=i 繥<ޝfaWey{,2OiO,XsLF8acG:J/k98w0sܯ9uܫ`2QpƬN32BY.<&]w żbPV̥XaskN8zT!7Ʈe:[,J"Bqt5~-b'K[ <,.|EE8wVZ ҨQ1?WU %x)υbγh:Əhv$Ӽ5$vo-Kš=c-6 4N};Tl.'>=؊!#N|Vl'g0xB*U]_kA|0>,0 浰ths,E)/ RP" m{jy!OC9{SeH>!7Wr% h~ XD|O _Q- [ih~z=q6O9 XW]sN[J(*iԧNX3Z0)1Їl9˩e]G븺t#JzRjEbi:P|lyj?cZ1ޙ6G7wNٹ YnfI37ߧfbU8C!kNb⤓h~`6QW_`0U&کW BwmNtܓn{jL(+^^Zi7յwmiikoK=0[4M+qFCԅ(Ԝ)Z")4I]ݵM%v$ZX8[saf'ď?OM']4Kazߝ>VmWK[]>+SӖ(K_Z'Ø$xۍQpM*8܃WEZjt(֫:tRJ\-^%xc7<sW> oC :tFr* Ko^gmux_Ú=cB-n3e{}Kb|iq15 *EceY~+2{OapOGJ|Tj2uS(|F- q NjU)J.&S#qySoٵ.xJiE$|O/{|;{x?D փZ>ZՍj]Ǩ6vv4z̶ؕ_'<8J֚L> oS.U({\& SJXmS7 מ_+Ü] 9W3Y(QxR^J*Q`ɬU ԩU4EGψ?e]msq2]PtGD-%+ԥlV/ThUIseҞ0էFx,?}qFC_Rx\^T xxԛ5cN2/i8VzJ{+Tow:爮|;oZȶzix[{u37rؒ+w.pr;sp8S9VI:ӥٴ>xU~'Tʝ*xFS<O RyWW"l5Ll%ρs>#[-RB*<]:TI`Q&T*1gYk7]P׼A|OvoxG M.?炼/ RY<3^j"]_EkJMߪ;'b ӖmW)|E\ FT/bp*XڵaFep'iZW}ֶ=v:>ZxrKHӯ{8+˸aWyoƜNiS_[IԧJfy-7c[-0yeM0𾅫~"[izVZn\*O}OQ~RI{{lN6W?ip}w,$=馱J8VziQ)GwUN36877͢Uꖭ%|u||-,74]7P𝈹.u]J]^Sl4MF#-[ ,a2uUEfOV5ۨSԝesY~cҧJ445jN1JPÒU*R'e'L~/DŽ$;kVYBy4rV$vxMãmK+5yneM>j/%N>I:jšPIɺ)ا%c :kW2voDzz$~K>ˍN'!YcQ8Cch~}ȸVعJ['8ӔNө=a sFe/~jN55 8y(ٟJol?i2^ԵߏƳi$o}#R;{ OL{ ہ[]Z,3LDQ;*dԪGg (J8~ڏ)^_xwd,-r4"-og* &VD3[$2aWKJ!yW¨Fj(r`?i)(.c\- b*SD97NJuje>E9cNW8B3S|ǿ]~ggm3𾾾u:ēzZZ5ƭx~K7/X3ϰ`pR*_STqSQYVK BZpdX2iPau)ӧ_0gNYUrVu[ks]9ƪx''Ws\RPmTV0~ߴO(Ľ LM7.Z]$rx_~4gm[_W?żz[N[kk"TR*<-z [/cJWW4c:쵩ޕjSB/x:R<=Í|,gxBm_SfѼ%-3G45CPյcou;6i_'9bqF՝iSaƎMԔ(УRJ6*q)1V1*tGN pbT=GCW,#A ( (k& UAP-:x]Vu{Tկ;CP*kd*7:9FSRQʭZ8,2u+b*ξ"F':ԩZI9NYΤۜ/MLn;'ʰN/1F*WJug 4(ҡJ2:4ӂ!G/τ_ uK߆ |;#Z/1b+''4>]B;WXyZ<]`VG J҅VO:cN0U'OԥmWi>gr|~S`+ՃR ֩M2tR*s8Rbx]mx>5< ^./[gEhYkA:T()N18|'^s|!s?uK/4-/5iky-K"[˩]Ȍ)RP J pMՔa V!u pKFSrʸ$Eex<eZxzZ-ƥmjԄ ›eO?oeſh&XGakOiiQI\çV]<4#CNOM o @s᫙n<;>'ЧgH֭/tfVki^x%U&W0\ZXjFIb(ӬVPMU#5 ZH% #uq8\63 [P`+14iV:Ӆja:U#N5J5iSJhz-΋'4}.K]m>]]T\Zش~b+LU:xֆ6CF8|ѪɹKKoJң0hS4ERF!J)tM(F`RQV>^c3_ĖHS}mvO [Λ#- >TB-$ jx> [ 78:{JpEjtJ.qpGΧ;ܪʧ1SU9y9o\%dRTѴsJu+M=N}7RѵK]CJ4똌uR\@ K䍐nM Uhc(ЮkӅzUwj: Zd]\~1"IB)F*#Gvh|~Αo~ #,S{^H9f`񽾏ᅣ!N<.Sүхj/RQug*:ОUG ՅZO |?Х]]XcHokծ횾 Dp(ԧQO FPҡNS*j4:1ufRIJⲼ()NSa2ueUXZ0*҂jQ/iZQMJQv5knm2 xRc0i:!ӭY쬼GaI,KŨ-$,Myج,WXN LBuy*ԤU%ZU*(ҪN>ҧ,W<2a`0ՆzQl,oo_c8*'>gN=G? {O<>NƓkVޭ"59ZDFcJ,=(B7JB;GNiU$J1R?~*2ev/VjuV)ʴҴg^i>%VRqAF1jgP@p~;Y╮c7π#YiR_iV~;_k^-ޟo ?PHKdgf+rb2.*ؼV*ӡWZuFUJuiTZXz8ƤQs\na1qU^%az8:RZt xTSWN+ՌgԚ i-̶~c:| 4mOJԭ>|?+)4ȼ>W֗E=ݴOo4qTeTqp8:X=HקN g jƚ:!88JI.>d_eg.Ȥ,/|uWû5YzGF>k[G7xK-TԠ;Hu dt$fbD+j|=ZlEZjWUUuRa+aJ.t*+T5oY3`y 0a: K.h{ZRNI.hGݖUQQB( 000 ݷ&&)6&zۻm[o_3x0aTa1Vce$Jh&IxZm/;UI:d$pϩj3Z { ie$w`f[ІFZW-*ukB*u^ 'NtB)r?20,= 8 ٦.jkBu*ڲYUWVVRW*r=NODχ_~|$\J,,#f-ɲzFSХNN,:tF!J1!r)%dy{ b1FGWb5\F+Zr[:2ZZJju'9JSxoW?uwStOAb:퟇4{o0y0pm 4pV F)V)BUJaRpF4J\U~en.U]uᰞÛ*~Þ||<ҳ\_'6.6t_75lVgV&29P3]K5z0xzx<%X\%)Jtzp9”'*ti4)I)E](`08ZVsbhaѯJu*J28F&ZZҜԓ?d/ٛ.7>$GGT[, be͉8{/ϚsĪ^57N4FNN0iùuV\B&-4ύo4cڅֺH% 7:\啤Ҫ=ʉ$<~+(q#V{kJeAԩNPZIVJ#j$OsL*Qe\|0]l+RjQak[ :IP_aGs{(#ao |('|<ͦkJӒ jmIQ绽xa1/N1F!GGPңMn*q8ʤ5IF)ԟ7)k)ʲ<#<>Qa2ueSy<"\D B39A(&z53 (<ǟ~Sm%'|/wvx^{hS|t8ޛ+3vlsKS6"8,EXׯׯ{8VRiƤ)sJO5ɽ[g?,sJtfy~2FrF? ӥRj1JpRNQc)EFMF)Qٓmе+Z'?G}ozZ~jV%Ŧjv Wu=ݜ ѤȎ<&pl6"0J8= T+FzU(WӄfZZjIF*)Jep=G0b0?p1*µeg*U֥J*gN8TS /< /uH3t-nb cF͕5HAZ1JС,F*4ItIt)a8$Bۥ(7:4tpʂ8,&aUV*xTS^)QS+UdRhO/R<9:fռ=M*Zu(+3QTT\&UuV c0q4y?g^*EN$jAGp&:*ӧZl=jpCJt1*5(סUrԣZԡVHFP]m=+'~x>-/zDj5to ?ږz֡a +IxF,kYF F"0TPӦR>Ζ"5z0qV.2Z|ʤԾrp 4 5hMԠB(a͇QTQjSPN0q>4 K¾4 }V4kEԠF ;IR9PKrH]UlV c0q4y?g^*EN$jAGp&>:uV֧ 1CB#RzW-J5MJiTqNe I߂bG牬GOQNVn=gjѭ,n!DbƱe `hb#NlM:j5#b*sWbJ#(թ̪MK)pg ЯKK cVJ :4*9҆|z5Eƥ:Qe8+` (U+UA  өԧR2Js' YBq(-QN7M4ӳMjj4M?ɟA/ٟ~H 9A#g 373n'}K*58X`܊=R^V<7:FTId9M?)JMܤmOGß i9 )xcD>u Ρ6{qokkoO,6#$(^a)RB?WFJѧBʔ)T^Zu+U$Rrv_D*rYNoֆ_WQcJ5+*4(RJ)g|8ӮF}^Kg_ ךE֩uc\j71O{4Os2E#QF<>N0hl-Ɩ IQF 4FS9Iݶ 3`p9k G,^&jbeJzI)UQ|De"o>xZ>wk:Zt&b&M~@&eo&yuvQ"',%Y֖[sQը4ԩ*U*Q\9V(Iηeycxg ͫeN**طBuQRZN#cFiD  7c<+y,tM&I̸l`-=܊7%̲_ݧM%t`QRI7%J(N(RqN0\Uݗ~SXLaT5C Fi=IF=Isԟ4e'dy/3oͮJ;[y%H>OjV ݚHѼQV\ *%OFou78EBMrǛ32\_ xPL#GgMy"G$Q8bKFKۅ14BiҧB!J%FB JrsMF>yR|<)˚rYy-ʲ&_FR0aK%RTQQ)ϖ*7QS=  (|uw V^kOMr=.YÿxU!-:Ql")R'cM# \-Vuer0*P,N.HXIYYhy)eJYUfRB,.2Ta9sN"WN2(JZZO/h:hwMZ5M#W~|<ӵM+S;GN,? ݍQ\]KŴ42$WC֧plE'J =5ֽ:Bpvm^2[K<'Дg8j' Ŭ*jQRM4i/_ #6x#oue= M4VoN|LfȜ1fC%KBX+*T' Rz.)=FWry}Lv_G `py5c^8|v.kFkF"JjaR#QGB⤣))dxZ} ~#W<|_uZO k]>:UVJ,[4qI"t,kv&r#*T_ ByQ:)RujRGJJN,'Z1VWScK Ob]Rw"Xuƫ**|M)Y\Yݥݤ\[|o͵qo<^YaUdXd]0] G؜5Zuj4kЯFj*jӥҩΝHJ3)$˃Jq'98N.3LQd(/ӋMZ;kþ0/ @|Qf٬KִMVgtJveVhn`2ʤT:d'N8ԇ44'%$ %(IZQRM'NzUhVN PF#Rj5գZԡVZr:Bp$<>|&֤'? < )`^kIiqYG}mgrEť[ϲ?9bXL&aUhV8RuFQYA)Tg8nQ:<| p]XGQRPaZ5ԅ%*jqn2P揺ܕ{a@Pk;MFO-m/+KKḶ))bvEdfz1T+a4ib0؊U(b0µ +AӫF*TҫNRJs8IIŴT':sJs:g N3ӌ((-'&i4ծx4_ ff()͟7|=ҹ?rW̿~i^&}ǖ<;F.rE}-z鯝T##^ O|#[_ xcz6]RIeh:MQyrM+oiTya~*e5pS([%RUC*c*B8:!MǙM/Kf(G5{x/m.tKX`H-No VEvClFW<&`ZHծF.pjץTRJsn&Jjտq}ujKԓ=~gÏi|? +"iƓci~t=Đin\I%C=̲K,#|tiTi(SJ? *4)R%:q#v*ܿ)G` ,e)JRwRQUV|*Kޜ; (,_oE; J|k^*m4fN5& /.#eIeT<\s˲ԯUF5+ BUF 1ISsRTVI$y)'FeٍL<\01,6.t FXUeN.m)NV)x[yo_?z|wx ym5Vz֓jVZ\\Z$7(O4nWF `ZxL= ,yS*=*Ƴ }ܡ(ҩJ6EPae)aqtr ,NSV凯 :FR^):s*irԺkxÞ2xv𗊵 躧<.Dr}SD7A6qQgFb 4 ӄq_VkFX(_a(qtkN-U݊`qU`}i01Xz5灯QsXNXjx|;J.QroSfe97x&EJId9::V)֣GFJz΍zkQ Ӛ*S 8N8I ʜ8JP$ e+8-&wM][CHn//rsry9SԌrWeOXn[vVi4ti5ϟ\+ . 2OrUdv*/[⿆ >Zi~ ޔ|7[iKMJ;M R`cMv-<Μ)Q:~.M*QNطKZrq=S,N4Zwp'#:Uh^h­>Z|(gρڝ7|# B%q-r6Oۙtuk{wxfL6N,xxjXe<^&~Y8{iMBr)M˸_SF pkJxRPtVR7I!'AGs (3H:kawk.cm:iڞ{wowgu 0HF쭕z14CF"K)ѯNiM))%:u+J*K;J)RpRHNHI'ө u(T ŧFN-I6_+UXM߳ASr!* CÞY Ay^WI(.8aIlVI[Em;t<( B.1̆1/Q2'uwZ=\/ [x'¾φ|gmwei/:V[;./-6J{bIggN&b)¾Xh` эZ/NpӃC AFcIASJr)O 0fJRѥZijէK Tԫ:'NVMRco<C|_xn <=iẻ2-'D@dI330#tPN:t((ңMԝW T)իR#Tr/(py} TiPha(ʬʬЧNFSqqSm%>6d"_?|AܛgR_\{^B-u˙nngաu802Zrra)UUJͤ{zUiiZ+-7N^Yi<4K&ݽGNJtFQN8SN (SN B((œ#09f< ai8aiХIN\b9^U&)ɹI6 z%>|6n5GDJ+*NvyIy%idFta2% a)ahI;K FMJʗt!MT'cx?3Ulf7#˱Mo<<qx*#J ->'+cσz+ym.4Py+YG#k )ƬiԜ#^ hrkSU)TҩV*}*s MsfKT9<$jN<ѳ圕ڔ^xtj ;)tƷ[iӋ6{'4)VKiiy џ>]O2*?& &Tb)Ǘl.j9%%ʊcN?y 5Z0UReu Rk3|qg_C7gDx7þ,mߛc|t״@Y~m-JTU$"?.sj-9ɫs2Kٹs8]9[vW[Kg}W5'}^o-[OBULԭ4(o,/-&HWUe֝ZdJM¥'*s$֧:5iEVIҩΜ 5,T%HF5 J*pg 5 3&Sa_ &[XYH{6Uėz]'M1Vk~ı*$v*]:njpua U.)Օ9Uۚ0*4eR)T&UJ)RRtԚ*HӜtVa&RVS~߳~aX~Ͽlu=*QO>u 9.,-n"{kwh&%EtFa)S*BRHIJq$$(I&wN)de8B'N#RH kPex2jQj;;ꒂ ( xw-uxBM^kh> ,S.m /QaXˢܨ5)ӫR*t(ԌgRHեQ)&U*ӗ Ԣn*R9Μ*Sr$է*U`l*RԎӧ9BWW|'7W*^Ƕ?:__U5bW<,m;xy<oiY4k7ڮ;ٻZ,œ[3@a11ZUExN.5J*Z2%*jւTmʹJ?J%ΪtvJJJU'5Jrrc1O 'Dσ<7xGzhtcGӴ n'qeV֖6{Aoi\VT! .)ӧnoe QRwnQ8J[rOޔ'iKe)1PU.UmJ18B1sj0aArBh6+Nм?iY:6cmZekEJAmm P5U ZԫRRIթ+sN9E^RmE(IY#(S(Si6a)9I$)7);]ɶ>}2|Heώ(-,-U khb($qJ+NU*u*JS'9m$މ[K#(S(Si6a)9I$)7);]ɶ4 ( (?( ( ( ( (?(h_Qe='uktGǾb^ 3$Ew-P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( ( +gxIg O>"~ҟ>!xO |2u k[~ |S,w>}Fž.Dgèx=_OX*s|/&7 bgu^:_W,7˰ps_`M>X0BK"vsl湞OQX0enO`q0չ9{JRrdf|L5gFU`7˰Y5,U>IN&FKKU:5p{f[<.+ƥŹAx.yv+ PX?,'ZHk/UL6eJ:4 6 ejI^Uh 'Ŀ.'G|T𗇣4="8+|o|KKN ѵfEW*u*>WNTplfgʃWb%Q<3Wq~GuL.jc'b؜|hԅ>㈖,cgJ?kߴ o'>V?o<L׵5񷅧5-<֯$Vw=VHW';Ң*SaaqѣfSO Vz%<.U,FxF+^ӣHVUzձuXBe^uI?E<ş iuӼ%&MWTkۦ2Eka, ukŦ2k<8<'ß:]g q{XcD]H40ooo'Tb0TjNYv,%YU*a%xiUT=}ggx<-gx$pxKѯJjF?ZFR8llpBVtTjܞMnwd<3|cjtjPxPmu (0?iYOxPEMyJu:_;5#P;!>W8b.RNY|R*8e,vW.N}^JuΜqQ_SB\faRRfbpըhbrJ)'IPInk$)4es:є*T'k^N ed}RjP@~A~?g>Au~Ϻ|K+<🎯uԹ۾|? Jt=WLd*V/K/m~Vmϸ?-`i43/ԯKp<=xOwʱXƪ0Tj>1>-p|Ό.? UhS mL%L5J>S:_QhяVEc#'{_ξI)I-^~_q]9ѥ9[t)YY^QMkewa&槃>|l{E+|$=/2ƣx6_jwq^XxORmS^Dw[n4O1Ye/r6[YexXa^ U*ž#61CC 4u[ w?ygCC2p-ٞ/ebs^8e08eUbcL$xRlߊ?cڛ@~vs 񿀒Ÿ4[}6[UNyysi]xzkIbWo4+Q7{g=+fZ5[ RJ*8/嘊'[̩cU i88pOCV>psЯ[WWYF՝ fĸW?j{7~|=~Oo<6uZƛ=*Pu9tUukxaڰ[Hq/O=)gOesS`0T*3VQ }Y:،eVgN5(Bu}jY\Ce1=^f8ZѩW>rVeø^,,991*RNR~gx,r :/4W:yѡi/QJ|)q}]܅P@3?g¥wSf%zOD jl5C˨\^ ue`ku7iUG\jӫ)Z(UXΥH<= ^P*N91XV˲ʙ)ׅ%m S'IS u!JOe F%{uR8(=?i?VaQ h𭼃Nд?K\\]k|ڥyd{{+^>'>[TVe; OT'WrVn5'9ԟpgyW8Gy *B,No)*,d<68js=JXl5:Vh?>x)@Ŵ^V`Iki4K Sj:h XYO|UV^<3TTZgӡB+QBa0ӥ^!B|ya27*N,N NE:tiR N'kP!R U1XסNR߈n? ~%Gxᕝx_<+k]>$ƾl+=Z Gh:N]Ϧ/Ro (g,(Ru:^ RUeeC # VSb'+NF/(U>'Owy|e> |^Eߋiq>kҮ|;OĶ>>ut6ĺEzVpɷN*敪PβusʇN2 ML^p8X8U¼+8)bӕz m[ ,^3NiNÆO_8u0LyRUkSb+Еعᣉ*E/|1- M(յ G^4mR[xoMӟ\"XH?3\NJrzR.Tyl(Хy2U[G IxU8үKg_+p48^u0uxy/0X>G0a0~FhҫeFʽ\6l>.|t7+RMB>07{u]^Wsip]kJNѦ;[syqK*ٝ<6Jr*L֔'KVpW&*QBnpQq^j:N e)f/SGEⰵqbC8* # 4|TYM~Ͽ(󥧅<Cp k~;$xƟ <vkKuX4[SY+(6i̳ -%K ЦJWm|wexWslkK2N+ JW-".+#+  (4@{o$s[ LÿNkg[V_]7 k5y2AsVL0pPO µ6XKS&U^ .Z4ҩR]ׅ/PVb 2,*55kRN_GaS_7?eZRaqը5Iþz0sVį0~\ iw43JЬ4 jvzb u Ǵ/SWsWvMV3w2QVfxf+V)ih{΍8cJZWRu/sN*ĵ\6S-*]  .*U+5zeVj*JN)PtOЏ7 OgK/.e_XYL,Lچa1yvŬ!e\0)gy>_ieS-s\~cee᥆<^uB GK)PJujaf9W`p!W;8(pT&KBx<7%N%C5*S_KJhQ ~ R/ i^5V=W3 c{<V0yee~sΪ_^Ns:)q/L&'<uz|J518\߳NOC֩(S(S>m?k_| L~' xaB+[oKmW_u}gc}φl{ RU"-x^>i|+ę M\֭OmWORF Vg8O0/6/<>TppC8pV }RpJ~J>7 ezl ULtxqY^,+>47t?0OKv+D~j |On<;ZxŶz}Ǥkk]m{uA&rf?:7.Y.e $0Q8.u0^EZWTRqZѩFJjU#)J]bz@ ̒o<@S ClG\J ,bp#H(&TK^ WFJ8XTJXNj֔iSiMT(Ӄ4䢛ӌeR8Jq8J[%y89;Y&Gg_[O?OηAO x=oC4z<{/% ([]KZԑ,Ѷ ˳,vKGyЩ]oY|3#Cx$e<5Wu#Vn)N'ð )q&UTf;u ^_+Юt[ڮZB|?~ִǛWy.x9a*_Y^)N4?ÙUd< C|,Sjklj ^]Zm5 3jbQﯬ4WLj2__ gT&ӡ,'ԌԎ!$\3,|/_W[ґ<-ٖ+3~ |6 yDj![/UЂo^1,nF/ zt03?S?jP~@}O/"WV|X??˃ĺƟ/3x5/nc-@|EAqs>E]W4βaL_bL4p][.`if!⨨OWZt΅'S;юm-|WmW ~+ Sg\6a`|&Bթ=UќK>;Y;_4+o~ Ҽ1+ᶷ>75}CU<5 3Tqjwt^Gc&:i+ &gù+iP`kj`UT~ߖ ?ѮUp9VF[N+@8E|f3lL,q]e8xZpF4Ejx^\Fl_unP@|B|Z_SCZžb'T/$<6vq_Gbm_N\\[9Qͱ2<.Yb391X)c+W <oo T% ճhU>LN?S̰^'S 51xWt{jSc'aj”j¤| ӡ|Z1NMt[ /6u^MZ[7w7s"#\Opd̮9KUSbUfB)F:ч5e.H|wQqnMfypSα8Z4tRG _(gSU)ի:Rޮ/j6xXo45xQG6:\,ruMJ;+-hm,u RMӮ,8Y`p^O2w]LXJ Qu <ԕjZ4kV\6 eƜ)S\]l?j\][bc7'Wxb0a&Z59(Pb+ߧwWvW^Y[ͭI52)+$SD$n+A**ԣVVIҫNJ҅Jrq$J2N-th axZQֆB#VX7fR8lk3` 5 ;E 'H:y6v:}ηmk,zE5e>pw\Acm$5@:֡[2*S,%:hԌo0^PNUQ(6TR.HMi]od%j=;x෇>x7֧jV484+Neơiφ<'^ kas۝uXצY;ƔTR^ﵧܧgU%b+-x; < ซcΦ3C2kQb2jxF` B՜iԏԽJYgUt}W\ aiڭEUӭe1Ŀ4ar.Qɮ0噎iIa/0J.1cMJPNJ S\Ͱ'PSiTVBWQS5N.M&Ҽ웶~W~?7q|?| x_vQqi|{ۿ<ݎj.'om`Vq n-e𰘜ÔXT+RK2%ĹxJ - 6!QNksN=Wɱ^eم</'gWΕ لmE`8>Yy'Ɣ1W}ںmǗ?Γ4= ݽZ撺 iZ\[u7QVQ`nquV:2_۔),-zj."bx.!x>RX,_1Y NH֎++ҩyөCI~|qmK^?!_ j^ o}ğU]B-GŞҴ K4ւ2SYQҮN2oQ]L.SƮ*O¼TObWab(UXz|FjAqnkSfÙ.)pΫ'b3Ν7;:~~㙼25o?S3 FM7@m.__: n5$KѾӧ7ͩK|tOW#*f,v\ʭzxsЫ{ ңexL6eQ>Urg<8E 7.'L.cR(ե<%%*!a^|qUW)~پy_k:EV!oK]b{jZk׮o,侇 ò5t`|53<ֿfjx.>|<*LH:L=jUTdQ218_a.3eupakasl8VO^tj1Ԕ0pjО=ROa_`~~eDo~OĹ ּeuxgNq餖Knac2Eij_;X,<.Zx,fccb+ v6Hᰮ5<µIFS8jQ,W-/6 C~cb1lYxJo-pjNYcʗU*X"|w#XxStt~6f*h_>x?|Aq]մ'KKFS ke{S8N?3,>cVEFSk[ #:3}w(Z!fg>wGK;IdyQxL'WYn;¼Wkb3' 5Z+J?kڳ|Kg/Sh\^ W<[+),'N-_Qo4M*{[M 7z>ۋ̱،*iY+{iayv;߲ø֫[C+ 3~Ui_q>13#adxlEia9hT+% ru0 N-c-Fx?eߌ|!Ph_s㏉l x j}Ɵf_uZL}F[ k&-CQ/t;\Mޖ;W8?mNR,;T-icqyvQzTSB7uĜ]+̸Edn,Ⲛx++aR׆',>^38u_'+f@( WkZ'_Þ񞽦wGu='F=Yht(+Rp362z%W : NjVNEW:tJs(\Ӎ'NI2(שJJX|EZT kRR-9T:PaRJtiΤjV QߴGrx:dF#Zu.>}X;K)Ѵh2h׵O'!1}9~>08~:)V15,*1MVVՇB:5=uqQcLjqMϫcV v".***8*y1ZU'W*2Մ?W?P):꺄maYj2Gogg3 1s©\n-cs\0~+ag^:ri]^ֺ֍)+RIsTV*q5+kɥ~z'_Wÿ 6='_|/⿊5:֏k|I:ޟZ֙}1,$:%ŬWzms/|^;(eK :L60RجWWQ#C 4(Zq2|9,=|$rls SV]<2ac3e::<Z.Iտe_?_|eg;]kMmc0zn 69M/T"y.V[4?(<#,;tԢ|9۝ö|Ωέ4}*m[gln^6;5 ?g{_h^{W~%WÞћC5mOQ1M_XiΖ6E/cĖE3Af2a4h%O1!ZH֎*,b:3^ SQ:tYee鼫 rk<ahUO RXTηӯ PQ)P*^K_߲ϋnMch`qyc)JbD0MH^X6 Sᰱ}4ك¾L?탵j:tWB /˲L>%ԩ참<-+}c2k^1U:'_ 㱸O~$S, q9fYe]?aEB1>ʬp*q_`/"> N/*N?R;5;QuyO!Ω{C"=?[k,|CMXuJฯ{Y$QK O(W U3*xaqXxUXʮ[Un(߄N[U1؞򢡌C1e_`'9FJ1i'R92#>^Nݿ|RWIJWW]=a@\/%~EXC _o@,vKooxL,Y^MF7ቚXc~Lm|NT+{J0*|<*U*UӥBZq!(RS:ҝ:S*iPV kS)Bue T爩хJӅJjUg jR?8>_wog? )_?|CeMw4ki7׍4k4Q<6`ֶ$6[ңaSAB.#"o/^VwȲ^i qBjbX)T)B3^JӧBFuӣRqMUC *,> b:QZhVѧRE 4RP<~ |K?j7ߴ/Uே. $}㫟i%ōwqmG_i\x_@k)lK{OG5˪昜-,?&p8yfЩ!+ڟ>(2;wak4٤fG+!9K;}5&&q噎<2*f]JQkABUpuFu!JNNUpXz0 C&s\q'fu|/V5Sa:_XJ5kZE% Vbp0bҥe~v&||]eďèh <6ћףQi<79_^>]$6z\V/~W( kW%VfiYN5)᥊ᰑJ:ٞ3F9a=#p3cE'F3S+ҍ)ҨάkP FN~!xşf?u o0y#Ŏh귐ian0XYZ!Ȋ\*ղʟo8ܗԶjrA(Cc1?ͱ9i_8Oz<3?gB1jq|⛏3r:  ( (( ( (~ |ѵ?_9`Y>=Q >.^+sFOx/$|A-R6욿}7I9oO3OaL1pÊ0(d> }R\6rpy=Z9X(b˹_4je_xkOl0jLQ67_O1*g O(.f8ϫ{\,^_4x D__?cߋ:ƅ{߂ҟ [}cg<[/ڵφ<_=BV$6+J8o3Qϱ8 ##0#Gs8b2\ j*4q*e53h`0?!OYɲ\N7%üN:,klNmluU<|r* mqJ]?'V[aX?wZMxW 5_>67PΧi5ͮ]u{Ṱx&YgtZYmO=2,ޞ. 5~E;EB_iSZ$qTr̾Wp<>F1C (8VjrNiNdS:5#$w垀P@P@_F/4~Ro/ ?Yhʏ,=Ӭ_1e?)5[5kzv˝J_w꺌fgwկ)0vga_7˸s/ia0Y}z̳ C4Ru7VqGx8^ɨ&/,3<z𭉩^𮤨%J%KUU/~i!o.gO~ 𵵷]{I׭4 I/-d׼W]DCi=Q: |ak3lێTka0,^0:8ET^8%yyT)fYl!W,?n?/+q3zkfj^`xZN[qӯA Y_ |6~dƭMvζ<$40[?+-.<לO ڢOxUrluH1 82iT(὾f ؊uJxL,kgU]:459Y_j~P@_c!(W_+'Wo^FdZk/>m'x|hѭ#. ?jvlA#+{kiTw~ks8[ R8x3A2bp.тtφͱ=u8'8/x'ظ栳,%ʱwI`7qWK`*RpzNRkzgٔ|{0xgB o f/U-qj|0_TFj.#md,.hu>y9f43\e|GRB/~c_(e,&XVtkcʸ% RZ0# 1neO+Qppf[,[0<ҾgХB8Lf[c* JU' =ҿjtgmχm5jΤ|;cëo|EuЦ[1p YYCv9i ~Wis "hKc_ K/ZQqp`e^jj*y7?1VR>>hSAZxg@U̚VՙĞGYRFH\ֶZ.O9e '%^V^Jxz1ЃQԫQP<5Zm?mZ\ e8,7ϰxog3z'gY>u=Z8yn&xG>x=7Tq:uIox3Zs&@ԡ &s Mr6q}G[33:(ba¹>S&ZU,Ϊa6Xӌp!gY⸷+`91"18=̞/6`hҫxӭw/ OطִO ' |c55?Z{wÚmPzť,7#vIvdLv3:sӧdףasWZ8yԩ^;K熕 .feLV5ʸYsO nb<5)}BsJkԢ6Wm^PP@PAk-e/NXbwU}Qg٣PZk s]<;3I4 $U^#mF\,xWǏ8 O2 q8L08x\5x.5煻-K^ۏ9MGújz.FSUPOu\}gSUaJN2Bhtb>3~ܿ>jap_S1;o ]g cmJXHB)Z(Ⳝ0b3?j_ۃ/~_|?╾o|SU{5|xRl;N)Y|Qe˟:ό5S nnY.~ r]Kw6 \"hj؜/518y{hQkˣOFVO*U8Pu'cⰕ7'n79G5dWp QԩfUq{\J*K )RK :<:/<{x?m{/ HtMyqs㳿ԡ5DֆK]iV+]Im%^W*T*μ%jZcԩc*ag%08QL=VQƶuQ<+)է cx4:n7 63AӯRmZ:{ |u'L~I/< heԼ5-*X:9+{mjvpB;γ|,+GTQ>"XgCF'ײ$aiʊeRpkN^!8 59eN_n.*T1؎u%J1ԡɟiyTX"qKj|-s+߅ε'׵;i/a/"l&4%D Ky{n}SR\nyөGs:U] L#ZII8UUhtN8O-ϰoZu_ui{zҴ*hPc3*č[5|ҥZƁj7X5ѭxHu _KnANkXOkJX'Ͱ+JsQpСR:of匥:q2-,%|Fy¯x'Ĝc*vWa1K}4S-0ήg*Y9'+Woe>7|/uGztj72~]f,xoPw^յ]hWvZHYh^Ҽ?k.u^FU8Zq.iK< ˃ri$5O1Rabp<E(Q9UVeX$~^iWexlMzQYF.p4kUZc xz|xo oh<|kg.{ >!uokƷ;m-c~Nw~ў}SX=v^oØ<0k-چ];eχu:a7]:;FKqCF@lsmxJX dv.;(bbj_WaȪ1o Lʴ 6QugGfagܯV1~w_aC/T% aab|2{)ʰ.z0HB[ƊiÈRYqؚ9oy:7/ObԖ JPnyKJ|CbOxS޷:Ɵxρ|;_-k> ҴWGHt{=3zLoycwy{~k̳|G \ձ9Cb+x|-/CƬ}a֣^ҡקeU+qD3&oS*d d%XJ\F2 ْBԪ`2ۮne"uC=+Yד:$hȀ[D5Ԩ+敨 Ô3hUU t(<:P [gb*GHC7ɼ4㬾zQi5BS`v?qjUkYn/Zxbqi϶vaq)EC_⯈烼EZRK~xy.gӵ9 R}u!h>s|M)Wr,v3)IKYuMq9iUQut%|Jrq+%j5㈣G9szxTqyu<> xȹю#%Q.)& ^Y,7!z0Y$݆fx±s>g;_SWV#UF3k~%>.|>q6SKX<J9+EfOCri0+G }.Bh2+cpX#(9tytZxKGV:ݓO$]1߃tNKYxjU9;7aBQO_b~P@|K,+^_|5Ŧ#״&e ƻZjVF5i[WӠ/"W٥n&Tps>6KQ_ UN ü-,D+SUYQf?g|o=o>hzCg}S/c}5/-:X(7F"oG'fy BԚ/e`a_aS7[*xD w(\ yceWa ha/ :u30l]HTW 3CNFxZk_|9 lŪZeԴuvGh wkg4h#-Qu'[lJX -ZRXLFqW 峎#V2Uh䣘cKq4gcʢ?>a6_,,^Ubjaq3t򪙟3 "YmƂͰ%|}Ni^⵸:x8d#ics+ (f,5JtaX,MzX:/ju1)pr.4?CA9AdG HiM4>mWeQc8IJ2JQZqdivi^ZC (?1geo7| oJen4?}?Y(jֺuYjM݅宨Lluż^˳* l򉙙Uc,K ^҆8\P_cR`aSJuiB4%7*M'&ծmjx0u֥: 0u8ʟ,,:gG_jc=_[?c xV / o)/-6Su_ Nex2!5xͨi~e8%cxdj0>mJ)FS5QkYf:X1c,oFٔr/Жwy5OxO_1}[Jҗ_6`ᆖ'<+#? fn{:ڶ*%BV`rpLJ^*UZXJO V ~?t^ҍ&k0o_G TX~WڟP@|\ɫ~_B+W{nط2AL'yV_Gd =x3&-AUyM_ ī_7t_kD>~Gf縺ҮkKAgGr-Zw G+x >-K XkpJXUOqG4e*+W—09Þ/ƵGlNIfq֡8\5pxqRIf,:^W_F5:x>7>;ׯ4+u]5ՏtN͋NQ,z$}5V[ylesWIMUd5:T9E`(Ƥ*ba8TIp3pu Ս\N38)Ӝ% v +0st.fr־T͇!E_V [_XS7|ui֗?E>,Hf^$raxĔM<z1YF29aqGx\70n; MX)1*q'Xa"FY0xV|E"c}"l*bG֧KWN<>2~ҿQc__dO+h"{_ºgj χ=|?m555ִ?SK βmsVg8^*#?G G}:tΆN5B2N%qW4xx ahqWW,˰19CE\*,fgW+3cLԬ57O4VRӯm|Guiu +yc6yOz*W_V SJnH;6ٽVs\/`Xcp1xZѿ-\>&kPԧ8]^[#( ujk->+K23_wq_j~|n-7ƟG_.UI.7꺞i#Ѡ2K qkeK,WWqI)q_̸oGJuNa)SV[بQ ԫ]hVt(SWP\ŜYcym̲,.I7ex.5jjRեJ J7 ¾:~i$mķi:烵]3ĺvy^~k5hZ6}+趂}f/w9M>ʸb˨C(TSvYRܥå>Zغ8& fs,φy$Ur31[OTB|G%zaW%[^ 3L_P!q/4_`ƱcX)|BOK$o4q\m=(ӜG| † F .hQӌʤԩU1Oy%fܘW<6a+f35K\^6yb*ӧNV8z^,~տoM:L_߳σEd{MN[_^U7w>>a>ȗvu~'75*8-JNXN+ڴ+ҡ8%C([ Ô0XuS'?`/2٫??og2Ÿ /\WyAP@P@( ( (IqIB~,x>;d/xgBd{oxvQtMB\nV?bYGj^.,9:W<W8(ppOb51SS`QrղQfx42=SΰejliK>yy}(᱘|-WOg~ Ry8NtXZ ^y:#V߰Gůŏϋ4? ~?~'|b5]/|;/lMR-pi1jQkk|+-#pO-J{5K_ _7%\>" e+Tr|Q_Wxl}| LfX1^Bg:pnX5ձ6'b0LTaV8b|u,>&*ըүJ:5jҌg/>( (ɯ#??)W@P+O=3[|C~5[WJź{I9aOH-䉕Cȑ[yoD kO%؈bGi}^8g?t+y [|x{6Y:,4k(ieʬWujI.Z~­'?kn_n=]2D]̞hT?HxjY!ATh~f~޿Q_^'}0->/U>=^1Ӵ|kKz%>Z-/^"X$ֲ5.&723t*X9)RaTca˰!VFZa棈 /<{f| qQvWJ+Q|5SKNtc:/g>i?7__w)xƟ j>(|q. |;]͇]#Z|f;V)t}Lؠ7_W$Ϋq&wRxTGfX V 39WlJ j(ƅ*8XR:q(!bxO87d}F3Uy|ppyfuI5x}Jj L*gUr|i Ax{නčNÞU?PӴ υ4wQeX/Kw f<1Vqc)QXOW{?b|k,02( > >-F'/X;=[[t糾O[q+gOb3m73qPi#.g*q$v+WTa`r,ٖ. KtR7W4%ʯ[Y~hۧ^9GC MKg|Q&\I>C-,wfK v<7ȧS0CRzͨdl(%jb0iJ9N)X5!)_ø Wġ Nၡj[Zmojƺt}3N_cO쫣u_i~'9{x:Ƽ"I _۟VJ*g1T)m:L O,FUaYӯT8X:\^wLpycC128|~QճufJX}Nh XiO6,?$g8U ae1Ul5 s 0Y~S>be׍CJxcQO?\_LM}Bkg^ ;WSs5\S3:1kchbkT^\%ZTcGrJjSޒEl&1Y6?aήCf^Fc#U+ՌgOuJn2/ݏZ]|4K?ē|EiS#Gi1%΃[Nk]It^ eV9NNLxz^ӫ,M5'R5*ѵ):38BTz ~uF]RYGf$ѫ7|E 8jP眫*mU>( ~ |+/xMWo|zӯ[mVthzX :V^Gy-!.eq[Sx3=1iV >/)ӔUFY*4:SnR_\*p~w8\mF{S-ԯFT#WPhBTRQnu#Vw_+w> :#^]2JFX5;=Rt[#m"6}*t^3 R$5RW ҌiΝ,VsI ۙpy/e4q\%\^*1H=:?ZV0BU*aq*3QY^0C- E!ī_U_wGgF tS}mhkf{7e%|eʎ6a?iΫVU)%:ནlN ]VSgYs,҆3`]*=SJX,4=jzJ52\TFn1ZE/μD/حQpuqXN0eq,1+*U8g:X֥f,^-ў_R _`?jٷ~+c}@3mQ4+C߀|=/j~&>k7y,ay~#٦!CY-'n/}cN96!C/ҡūb3|N[_}B8άq[ŚҭCOh+\.`43t{sU,ގxSםl|.c*5O?1фCׅlFM6yxslolm9,V*u\Cѧq0%?l*G8|$5ρ_'+hgG#kԼif5,F}Au.~TυhUqN{ң^Y6#֫JTkVWUU |:ԔX|%P'm7 !K0FVu៴Qb3(|\tc R^1SZ)~ٟP@CzV|a=3[.uqzWvk-xEK&U!I$`+*x]<=ZqR֥ѥNWKN2Bwgc2*fxN&iRx疞ҥ,&&p]UHXY~{A_ƿ,|+|SCNtvO$-;F̒],[b.iԢicim؜>8q5G;YJ_v9Ⲯa) 1[9*reSpn5710s"U,F8-L>FT^*BagzQTV15k|9Ǐcy/l|n=k?P>{bxlmiO_hmnc9f9ek+b)S8js C'\?C?G(O25<9bc0x5o/MOb^L%t]P׉aǴgOnj>5~~Z/>,Ѿ&#׈eYA"=SMUB\?<-j?=s9`ҟ',.O0hdzMFVbjG|Bɱyzn,ʵ<7E*RKbq4k#]'fOٛ ⏉ Y➫3ǃmqxM%c.~MzIAo/W0T8w81ƹO%8w;vcJ4˰qR>K#u)`lU\1^-kIe7ֱǞ-X#^&]ƭua;u5ymo/gkڸvMpg^MS⧚:u`ucMTyFSW8 g9>7&,^ZU5ζ e36.QK x՝fV=_?~ >|CKup:Z,t[eO#QӬ5X5K@1gݨgwƔ<R_,MHΝXf V:RrЯFZaiTVteNR|./`pٍ\F#YJ51S)ΕzqX)RCF8քIP@Njo,Texԭ[ be{=Z8nZ*U*0(%K_t=Gğx&c6*-u1eBtÚJZU'Ӌ|N0ҟOo J~ xmaxwzchR+MjX&Ō$'1gX2+*ԗО*hMFi QUZ<qOx/:p/,OE|QҩЧ^ƺRUV*sg_,( w/N-YO5+o+?( *P:k{y.$kݎ+x2aRXFU ,c9׬ѭFܹNyr9G9qya˰1gȪJ%J4NjN\v~ o~<Ӽ175{ xKYխ/Aoz6t^j}ݛ[GyY#Y/! Naq;-ўi噍V Ӎx:9q՜c5iF}Ej\ԋNp6IT: B c)fTre(sUG}Z3u)rZr?Dm?D~DZ"s_OxTbje]5OMo[Գxp&Ե/ϵ\RNTkS©c0X78i7UkCt}ToqgC;ymlן15Wֶ, S~}6¡rI|ݍ-h'qu ;aVc*J9M>Q1գ)~ri;AǞNQjݗ[YF[S?b.sDoxun%%hX\,+?xnGl"n)gLU[N"GiN6U'ZkUܦ竓g~U.f04pjµ<.4⿪:УUBM:PQ l«]NN/ki? ;{RM$f$?SnbԵ=:پiqg)OvTg,_/iӫ_ISѨMZFtkqN:zKU`ΜG3*s N2u)֫O F*0?_'/֯';Tf΂I?omxsEtKV{KŗeYVG8gKZPlnqRuG4k{|UJҍzӭ5AV4f?kI W:ΰE&i*syu*R,-s:P1J FWG a}g-_^![?I5wjXXI{k~ӵMFW:مۡمr[l~x ]\V_ɂԊkcp##ҭZ4œfB#c pi+ex\ʥyRBRChʕ TiBTҒ5w nSW!!@eEgrQK32Ik:iХRY(RNujM t9;]1M/qbRݶoCk_)xoũ|S'Z J$)qxW3[$_Lq-F{jsf_rWJ̥ùxNR0i(**UB1GԆuRsa+ggZ:ٟd9QĮ>gQ2RWxkӔ(bhW%(S(<~ƿeGƭM_j#GnuD@$ Uⱻ}>hDi^\qB RjUQ&<>YF"7 Z(eNӯO J8Lf4%**R /9Qɱylʎ_J8uq:OoRv>>x[⿊g?7xSC΃s 0xn[hǁ{Eey4Z܌kne [:\?:xJvGo4|TaLu*)`2L<;UQJ:59lWXl8VҍY5W6+ :~W,FkZQŒr~߶/^ 5Ɠ_4ZGgx'seaxwDO[$77i+)'7b0qYVE +SS5J;#_%H^)`0UqXo87 'fYp8'>?¦3[3)eXzt)Uӥ`p%ZK /?7w>;|/_7X|o& OUӼ}7:otCC%j}tHDKO^udO>ɨƮ'OC.d԰zإVixՖkRt} S<%:F. 8n(q$33 'jta ,[< ʧ, |5ti~+Fᯋ|7fl/⾽}sWu8#OagC_M3K7f{CҥqvwG fyV'ˣ*Sü~p.cvPcBW &TUlU4h׎22[i\G? g:p69Q+*_\%G1Ͱ֫K0,.5p4pX_תc` (ڷ!W+ZO|G/o 76]v]ӶUOZF*ӧ&NU3 9v1ԥ:xV B*WաOBJjp NJ2B~?4oW^lkM_QMKR-%^m=,u[Kk-|c0ț+xs*< q`Wk75x,1>t礤R!oUḏ|A90C0eBj6"ZN1|pr7?ڗG*xxXtW.ccA-5cMY?hFŝˋX:𥇡])B1?2è~Xwޗ~*8ߋ`l_^#6yiW/TTcrLf-r$:x|bx?[?|gQt T|3z|BFNI_-ґK_hֺN=%ԯ4JXz6wLu5y\]dipk jc3'Fx,ԥ<pJ6x Zi,\^<Ҍv7;C/cteVs:ؗO/VPSNUrbQ+L%* nUv=ɦ>:λbr/fVKro!̿8px,VYaiTLFF?e?gc2?AS, x$`0Xdʲ<cj;G B; pVUe<-LW񘬦7 нh C,>m:9%<"ZZ²Hܻǒk\f*;UQL^"&iXFuJr劾Iicl+FWaʲ]BUNO jMN}NH()jZ_ڝvzneu"KJaE$Bڧ+a8]XaJXʭj:pb޶.9֩N(ԫ8ӧ9J0K͟ϗ;]~ξ,?c_^OGmh3DMXF|9_OħTBTxVU,sO`/j%ͲKgnUb=!VA^T˳*XY'c3,֮zpx,N+:+B)(ҝLM(PRJ*㿀#KqYź?е}_4.o,aG[i"{󪹞/fBG`:8jS3Lv .G*،VxISFb)BW>O9w?%eYdui'[+JL-*OC}j(WF?a"3|]ټcA+}ψl%h=EfX>Ը)Ùf>gb0\kW7[f>q}F? ,QXXKbjc(fv f<}YW<%t1}^s\J[X| ;߉-xh׃ ~?x_jVwzKxNG]:]{LԠӆɩZ_O6p ce{cbx*8\8,Lੵ jYh+VOK Wxq [ǸjռF77WAǪaV\<>[)*T*Esf;hO~?T6zCEغL-1x)a0zX|Tj Ҕu FOhw_mګt_^%IY6xgLּW[$WRiJ|"'֮h-z9V}c0 [3eƭ,]<|µ:=Zq1#ʝ5K%+ WӒ%(gY~ۇr\efy)`c`kBsX:\>ЧS e؊c (# n>d OLNc|Z%Oo(>v$A<'X|4}OZxYZyfO< U+<>2CQQS𸊕ү*Ҧ(q8|>/q32YS߈JpykXzP7Wui}OJRc̯γ[?dݷ{>6N#.O:Xnrf!FVUt0ubѡ׊$,MW6M⫉>#akY"CS7*aNu__(Ge*^0UU(bK TW3 OӯuWl8r 3f)`SNU,SVKB7 Z!GbQ>zslص 4)tx^񎍥]kv _t{Y7H#!VXf_Y 3ͨL-EΜRkW0(ѥ*%WR$zZ`|{2\î*e[󅇧*(VbZ+pipج gVNXO )`O(=35_'NCj>%o|C ? ^[k+ONԮ&n Z5}'W㭁]O(5ba>%y8z1*B'O ż=HVS(OĬˆ-2T3/S:x^99|qөĿiΥ\¢і"vVv{ğdBo f໛nq^//V+|ܾr/5{^^X 3`pX7%7aq$fQ.e ˕K+PՅ =._iVzB s"sW[j)FIRRI0JRrnF&ޑ??Sg_Ľ;PK௄zτt>+" >oׅ|A6lEM\kSDŨ˧XC>by.+6[ yv3ysXjx 9cV-/l*AQR`(ূP\D}[>,G&&P5QVeT#8FSx~YFOø>*W ٵZ9mZ~R*3'[NU9Цv8s>jڧ)ᛏ ~~:|'?]E\s'wR4mNKҌwo5.k%ƣ7#EhQkY^3<|z5 ΑJKuX5)-!}wֶsx0M-, QfHc0Ouz3Jnt*էE)pZ7Q*((cARu5o=jqԗzsJy}kS (> i? ~ hY_:N|qo?5;{]|;+=:ٛ"[魭cyU*ʦc%)siVSJѦ'RU$#F_? \~gm2EwT׆<[K_GR7wWʞeȗnapy/q2Ꭵ8¼_eXV5JaQǒJtR9~i8k+V:;gj]YT}c洞N)b#*'8UQtOg?c#M-WP6#T%tCnL{?{x5ϩ֠o'N] ǚ.H}_WG.c]j7Q4}z!L/|Mf*tjx5 pU3fyR˪jolj_i Q>&7Q1_x$ÿښsk.ms⋨|i?iZO]2YYO 'qhb1S xBb҆^HKթ).!d%qY'پ33`INpB<5O(Zy408jKL Ǐ_wοn?h߈_ <9? ֚Oxb@'u-J:g <7+g%6QB9e*5ꔭK gN1ry=\f*hC5s:O]ȸy|T|3L ,3/ѩ sLN0S(׭ Lp1O ~ݞ%b~=֗/RM#Q_/[[42C}V!iV -[K>"9:EUqΪ`9vXLF8j$g/ayױ?ĬgU#G=ipҭC N`N4c*6U*եN~'+_كp/4P+)޳e/^tbĞ+4 5 MKrif\q[Z3ȲEkӜ+2#VS^9jbG: Nx,//x-̸JyC^}e| e]U_a*ʌjC B\-I㥅bS^cm]~WI7_!0Sir1I CG3//A/WT0, b*Ƥ)bЇө)A{/)7]SoaFSkoqVA?|>eJUp#.st׭uAjh8f:Z4]ӫR3rׇxğ Oz_iv:dڕt[H^qmfdk}_f#ɫf ,daG/Fj{(TT_HQ+*5j:Rqp|k*q >ަ29m Mj|/MW' O18*2S<{WKxS>x|+V+RmqoZJfGuk?^A=yYGͳN pz4X`ө((կJn*mQT0ǒ?S Rh#y5LږSS Vnpml,#*Q㧆5'$aqQ XQsğ k/ǿW~_ f7b~)֝ E k:s؝R醍վ׶ZM 2[f^<ZbUsUJ|4U|WJx%UWT/{bx ܳ_ y{SCl}<|kpZ*K0o R`;˟I<]~>: F֫mD53=-/.u SX4yo]Um}2E0o p 12_$?<{|4m|sc-Q>_O jh|7:u-GH676$*D&xzTj`qճJ0pm\M_oS*%Nym&ҫʵ ea*O)qV7X\O?{l=YhQR)(Υ(NqI$($M$c_C M 8E^*9$jFI9$ij5L;]>$#"p8QGGJMoDI.ˢ.*TiƕpJ ЧJ8.фRUvK-R,( ( ( ]^74_[:֯AV:L7ڵS{^Ea]j7e^ίspQLѶ)ӅTQ)PJ4iSJrN687.Xw:)NZTiS,F&:pׯ8*եTrfYP@P@P@vtV/{Iףf [it*aI -cS8ԫBI3JRwJ2rVz5gƾУvzP f*FQWOMViUZiu)ogaam GG#pܜܞI-^$쬺"RFiQ T tSE(]d"€ ( (":GGՆYNC+A`iJ1e J2N2qd$iViiMZ4>36/5? ]o:.sfO4}.[L&dcTPP 4RtB4%ʛbڏ䥁PSC ^jXzTT;c9m7y;[fi:uk^77femבn ]Y^E={[d:Pq *VjtTjEqjc(JP\g+Q{QwR[ ?^ }/&k4 fbiJiVyqJ(% p%8XCYr%s > R Fm9F&NJb7}P@P@qz~,|S/T˩ko(/j677gaq~QJ抴_RJ/E># [Xl>%Eri^3nVVWm1"$HƋqqDDUW VmmvնޭcF)F1J1RQRI+$I+%x~o3ž,m=xwGM,ŕX% *P+P::4V (Օ8:I(ͧ$2I1aظ*X= U84քd՜*FqRqѴmH`(a% QDR8E"U+fܛmݶmߛaӌaQ cc$%e ( (KSMRHE9uaV$Rc4(ENI={MY4bq:fcC#^+ K{HB0dt5g \;|YEE+E^ZE_Wedޮ^1 ۄ#&b։%v.:$ȋ$r+#ttaGVʲ$2sJQ{+mkZ?"k"iu8dY\ m@fTb{Ei{^he}:+܈S' p"kۙk_mmkP@P@q"sڏ< ja1kW6Ԭnf#"u+I~CڪnjN*ɪM-{bV/ (+BeTRѫ|qiHE,qGhQDEUTUmmmޭmM*1J1QbbIY$IY-P@P@P|1i$I_Jai,y{J٤slsp˓*(WIVJUZpu+?4u1V:F8V5iҫԧ4JN2I_ut=BƙokD<=N:ev{XC1,(sI-H*HmbRkCCaQMЧ P{H(ڻ][iͥ<]A51\\$ƓA<!Xf@I#udtb *gTԄjBipT(ԣ$ԓꚳ7Mtkfg1x"| D_|<1@cJ.֛s uJp~ƔcJ77)Z\5WJu*ᰘ\=JũCJ]#)민޺GYTuP@P@d?>[eo?AI$T>$J #b&v\xú|oR?.\1\:m3^ yZ5>CU*ƽ_eُG F,e<\,F;ßC⬇-p\ֶMƋc0RsIT^fRqSU*J='O J/&' oO?iA-O/#mQ{ڄ^,uuAm,5k!.bmc x^q.6 f3Pa#*l5||F UЧxqxn 2L^i>1d;aV*pWt9US#NzULY̳*xX~_~_ ߳V|'U|6e;??}5/Nό>x;+>>KV޻پ$E~ -4]C*S3dL_YW>?_%S2feO W,ybqX 07gdԫq._C1YOeGGaW YC< kRH_x'|NO>+^fOWޛx*^kR |l8<F50^:Vre1uRj0M0ѥU B AMΰ_4\®!{F"U!')^JGWz@P@_F/4~Ro/ ?Yh_(gşGÞ$?4:[źŻZki6"+k7Ff$TW-^RS0gI*X<~:T"やeFi'RN5'[J~4GW2{Z^Psʫc+:uф$R>h~x*K 7ww2eҭ&y # 1 ,ڕ:9gF:T e*t5>ŚI'/cS ,)N+ a殨y7)J2p5Q)U}oz+P7oG'<O\xuok6  =6k<9 Ɉף F6kƬ9t(sJq8FױˡUR̳F^ueB񘯫abOpJu./ :U9ԫZNҍ<Rթ8Tn 3ҏjʈ+**4"r7 ¨M9I'&mE7uܚKDw#(IF15I'7;ɨ{$ (/I=|Ouu//S ?A6i:jP O\OZ5MfXWRr”Yb+c"JU9^Tp(!.'>eEBmJrÙK2E |{R\',+\.2/e s,ChN0?;x9"Z32d_ԣ|@/m{k5KŕO x<*)bkhF.<SthÞSn5N&NV_ed43 sU0yE,E:6oBk bjʭOgEy*֦sї#x#7kԯ{'yNTkfxF/ aRSj …Jj#Wp e ⏀tzįwu S|=ͦ_X*+}<:;CF֒YkXnaÙ~a eiqn< XvNJt僖8v+oգlƝ<~W.UPս^88Φ*27*|'S}C~ ~2jEx+}ivbX[.jM.QnnX'o !է–;-sJTMT yY!U JŪEb=J~x|'gTƌg ey3*WNs*tq5pSRt!V4eZ>( l|f> x v,IZ]7$ (~$jU忈 s[nehth-;Ú}^K,Qx]1?X_{c0n'/^ͬEz5%&܍Ư?,7$Yl54pI:TJ/Si.iuyNZP/$rJ'Ԑ9*$).M~'%JN 6_pC+b'M_> +ῇSiZ*~1^Asþctj ^xc[ҵ=yUSӖ+S BU1-R.Xzc^QkNpvI Q찳)b߻ ҡqM8q=JQzUdj'GĞ .um{kz֫xzx?GoU/.fTPH_Oѥγ|=F6*qiӧB;w<\rrr)6۳i]ҲnOvg~O~0+'ĭ{_h~'|ď/}KQH|G~:/ڋ2wxgelRiVFS(œTUj:]L=8UxfB+B橀Uwf3xıi1"W3"Y,4Zւ䳰Zi/F['aj5aFjqIJq9,,ThPQ)ST0R2yVyn*Yt125N8ΕW5Rt+T)FeSO2 (4iP`4xJK`iOKxʔcPep \b(S:mbTjG^ FH[;tbi /:ojE~7߅?~~9ִO0'>{-|/oz5]>Kk+o׉/l5Iod/`{&|M[6?ȫ^'g) 'ζtSƶWu:0m8X?182[1<1+{,rkcbbjt|O<¥*1:54 F/~*Za 9O?xOz<ڦ|we1angmh|^Q/--TL<ίeYb8\MITxz5q7SX/N51X)RFSZZ1. /VqtpaRU%*Xz3b+N*i)VگşQxiM V,lEeEY!X^IVoiPꐯR7W*SjO%QΞZ,F*& F' ,=Y}xG2\b:papU9lS14hľlT֊V:8xq֙A@R7+5/5ywkWOt(o?|+ ź׉}!56hEhZZ_Z`Ҽ;3y̖t UO yeNX]*\!(VOoYA*xJp/RZʍjGb,7*2gL , :q+b1Q`Z0xzսaK **Wڟ (G8Hѝ  $kEzx\=|MV,=8N%Rm%|vKwR9Wmw'dV~F~οc /sFo5_4 rzJk_W:l. N4Ukɧ>g%;&/2Zxh6#*SʧFp_6n+3.>K K:Mae;E 5n+)angئG*҄28*+,My~iߌ_/i'sx_~kxx7FԵ D^kQCI#$W9x|2F *8U*pЅ:ӌbމ$v;x#x;1UרRz*U*ԛ96ݮۻRP@x7Ʒ0~ڏ$usyHjl.<9إuoh) Y7k5=m|8L>]SF|g UJ^ WZ%YU\-hB_SʧZjc!F *22NR+|{a}V|aGse{i֖VZU}-0"B.(Pv/~C9WNԩV#cMv|EEf!:ѥMBiҧF*q#|33UqT8ƅ8a0P5gRP^jj"YӏmڳN~htdWMZ7ᗃT_4|-:>o lGU3Wzx" dp>TR*aJTjpxхjRaiN,F/qO8GC)Ot'WYp8Rbלgpxoinu.q>"k-oy3y Wq.Y 6mR8-C긪Rk˪p| *`1txmbx?|x3T90g@6^]#F b]^+M-[M!}6p^ bp|u .ZU`'{*}^yA5U)ν:du7(|.{ɂ&] Η$)Pü,3Q$0RJ1?8ˎ8Z*oHT.s2́$g4+F_OYVӴL+ONe[BLHm-f >d;KC*ae\+ME֏ e^b \g:gJPSPó,7Ҟ4ſe*MWT(q1L];V3_abnbrթBfU͋F G,D짌SZu1MƄRu)9OῈ?U:~ަ$6%+{ k;;K;H V֐*[{q7*2 x\;\)ɣS%l~̱Ӄ祋M`UKbTWx\>"%ώ;/_ϊO5OOk|7~wokB_ux+^繲tP ^'+Xb9>'3eyJ8ʝuha+tr*jLeU|g~y x1ɰq8,es\5  %\h<\XsףC/Q"I#8GTKRdIcuWEW ꮬ _Q_'Jje(R9Atnz`1qpXBTaq;B80+h.T-'XP@em& ]hk"SūXZ[i^VK{YTO 8y)41SO *zi֫NNI:kGB'%M&m/5{~iiv*Ol-u}it)KQo3 ΧLƭ*#hdU+|P+OazVj<*8|2x? ߍrӀc1Fq?ԫ`Xb+ԫGՎ71ҧRZOkxWANPB˳j&[asEl3aRSĪbtKpX>3)zجej1pB!?ʸc0T2<l SF\%v'X O _bӯKWXƇO~&|a-6Ovqx.tKkG ӢcMVKc47*8e"FXl^MBo8´c_%(ҭ00tg`*WV1l&?qK<6/:1pBaAҥNJ8Sִ5τ5` RI^(˲<9=FwUdUYVUMp8l_6*T~ۗ:kN59骓Px3o;`9N5|&i[+F>XcNJ+~^)߇~4|}_ /GÞ+{9x~;X./_OMq${|'W6N] ̞tᇧK4ЫAc3<#J&y^،kT)8V=\;[zcS'x:t XxbqTj }nyV O3G*lµ<4eق (h[[Q''ÚWg\'ķƫ;T-+#?Ocoi[gİ-:6i uOܳ;pKdoRcR ա Ui<R*RRUWJ\89'2xT~:XhU |&O&cp* ¥dS'inh}W1kznLJ$Zm'OԵmF y-tGTӑ<Wiur>[ 8as5[S˲ʘXTF1̳*SFT#Ja)kb9elU(b(e|CpRp<_2|+՝Z+PQ? 4ĺG~5_>=(-'|G{.խt1|?/%wF><4xtŚ[,ŎE#eJ.8sq/,Lqٜ5CB ^B#5ȗRzMjRRFZQ5f5&]̫Y*U3{R1iUTJ(9Jըԫ#_H~N\_]C_|Yᇆn?~7mG#?7kwmryٻiW3[ U.x6`rLڬ¾'T:X⤦*sSelf CHx;u1Ѡx,-qz|F#F)ʔ G 3Zξ, ^QW)oV_'>4|\v⋽#|[xRu˽36=4wMgme =C$iVZp~AN2u1X*NSb$՜1UZ9_/>axCsqX׈ej(gٌymC SNҍ4QGf[oq~ў4~'k?_vO hƉew}^W/Qm"T|&YTʰfuy9GS)˩b׵˰Ό卧6 UWqٷC2ϧf9'4`x{,SO8|R'Z5pԩa*8P_! }n,u/߳gU%]z=k_^d]6kamok8kxxk7iiRf n'%ϰT*J,>cxJTU)rOc!V0 ys$ fip9K,$Wc*`խ >&jF0`Kh` (>/Opx3._>h^ WKGK7~"P?4-KESya5M#eՖ{h f\CX YNʖT5/J*?~+ſ)+}_Í^V/_AxcC񇋴 *|xdžѵ˳B]6kaW5c-Z~l SN2aN,-.ZƖI`jiWĺt*,,0ɼYWeu,'8n>4p` J*28C[0įŬlB:ts? ~H{ e3^^-'G7^1 㬷"3d0,u,6S<<:/ħ%QWacbqx/Pnϊ^> Z<& G-bX}NP`q<\]Gӎ_ NZ%Z7α8YNZEΫR^'6/캞 43 ֦]QiSc1xmxT(X<*j刕_Ğ"|!w~#Jt}K_5;VO4{9 Fbo*ihf*bUk2Წ32ŹG qs(RMZUkiSFj8^rHCq4 ugtyTRmB*qNu*MST}>7K:࿀>O#Ǿ5B<񾳠$K6"X[<< ,flF/*2ژL> T(F*#צ:x:t1԰OC800?~:Y~_<(l):Rb1T Fp9"RN?iV~#Gj |w/n^i~&ѵoǏzƿ_?^Z(lJΥS~8K3,3 /XG/c<+M_m_ZPx*Ӄ|yW{KK!0KùG` C4(K G FRIОJ%A⥂|\3L§pWN'ptⰴ1쨪scԍ:TTxeC JaD ( (( ( (bJ~x'Hn M)\c%ٽÃ:Uuq ?Q|{~~ƈ?5]lNi1jvKn/|K5`aIŒ LnkWvP9^)x ,_m[W:P}x^ѫex1grXdE:x$kZ3&…)ׅU:8?޿TS+ZxnO>+_>~q|>juоˢb g:Tۺ],V};)K.+1Y_sD̫C+*ٵҦmQZFU㉞U ].Ql>Xf[O&`j iy[%e2YGW̨tʕsgڟ_1+Oj i3H×7mZ4.5 }ZƣA-?l(>ie9'SbMjq_XJWB3>"]UU*{ ӝyrsK2<¶gPbiѥL^ 0Rec1ne %Zխ? XZhѫWTJ8GX( (k& UAP-}{6Kn̿8C]ئrSO~ GfοsUOȿIث.JG]^a~f/_p#;sc~Zz/o̍?_Lu[&5Y/d)V{8>x ^h{*uN3k8FJ旼誵棯,&֭%~5׿KsjN{iK˻/ l EiqX̎]Jqu$Ҥf/Z^ө fx iጫ(<5E< ,e\"U`QZp~՟ 5ůz'uTE͖k]On֍Ypۼ,Eo&lm&Y2xz8|SBu,>siuUz(:uӫ*t:(g(JcWNY8Q[5m ר*t#[M֩)Ÿ4¤iO?<c=oR >x? 鋨xρm}.P: ChZj#$0ϲv3<.3 S0UxO:i|ƼQ}^PW3Rz+DŹx.+bpx#R#,R[xZy}l&!a8m9bV* cjc b ⿆P3F:#jxkj}ƥS%Z'߃L-m <:x:K^M7Y{JH1Drl#,Щ*0e 4_Q`Z8w#caR,?SɼD\fe/ΰIԭV>⥑bqk,v3-Ua$'FEO|e⿁g?G?y-ť߄LJ][ j0y'Eݔ_k]O }} Wʬ145!W `J:4ѵ /e5ptoNyi9uN}K/XIb([QQsZqRUcc2uk&>( ɷ5?CZd[p?XdDK ?O"/ ?ԚTo1__^^c|ƋU~<_fG?d?O}wA0Ԫ`lOZgDk Vh<suI-kĉt_C9^m.UR\ПP2Yҡaש8̲I(~ BxU)$ZTS*KC9Ч,ڕJ8mVcU'cyC ЮVnNTjaɎ|U/*o\|⛋ &=gPPsG=\蚌sA*W Ӕs+'gSJ&W+B9jJztg'NEV/%0_>)y W" O/U'MJ ,U8TR#P (_$7l?:/:x[&ˇ? _?تSC;~Ͼ/Yxs¾+&Yso0l; xtAayrmYŅ"ɵ{Ueجrږ1ц&+:ζ S8MZC:^ʵj4:x*y IAO5ʫ੼UIªgIXR:3U9Ν::qUI|{Q-6 ߊ _,"kN&4|-Ll൸`vW6puJ{]rvhNQ~i'Bw`98:fx:=:J"*pUQE{<QsQ% x_tcQk,Nl#79.y|{-j /|K^dGKĒ[ m6Юn.2Dv%; UYgul/Vd|=FqrTzO4*+Or?(NYR2gCiJoЌ\*eW3ZT3 Wyc"\dKג}P@Z<%W%Sl?KKG/M_'OcƼ#x˼UQ^ǿCD%͒xok> X ?K6kq Y}Qs Rjd9 '?^.WFT:|'ݮa6=5v:vckx}6(u .m)̸Se0MBZTj (xc3 Rµ[ <8\ :V8|4rIU襏qk`e Q92)18|*hdx>j2-Ƅj҄*ԝ/|'72?'J][=/"q oMM[:yeXckwxB+qSWUNOQb]&*OFs?y3xk;yWӧ?0W>,^T凵XlU:^H*QGP@~DC?[3?[pX%s/VqykOzĀȿ,_/;K%cՆNtKDODq\/*gR*^;';xm| x/-q\l;شybÊTuqt2<>YЧQ?mV. Ƅ %y'J: T$OK)o0r&WMiS:tcY**1u,_%HXWMG~_4ρ+[Pnu߲.\M-q_xzΥrjZ<s$:|V:|R [+tOkR%ɖe_RPTK/JQjQ)ε*q%ZjOW\6*jm+ʝ(nu%:*; (>$g9Wq]dQe?5?aԚGLk?9FԢI^^a?!$ce/UA]5?u(/U_⩴[Sl5;~#!j|.:>3mxEQ0)/tic~+ 9 UP'[ KƒΪa#Q:OX`ָ` OdžPFLrltbcυk<ǃV]S)6փ =߶'+? <=I|7ϊ^ Zuhtۛѵ,|>ugn|>ݭu2vmcvwXx~OefYFacicy!Vᱯu)tRlM\."x_qyv?̳56U̳౸ט*f^yO`2FOZlt*R/ + O0x7OR-R?4=!Kc')*8j_ |aS VOu!:xEI~txUf|!j|K SB5 kֱ yL}6^McǺΌQYѓ0}Sfes9VTKURX\fG J4(Ƭk֮9jc.m™~_<=g5cB 2faZ[ ."p&eN_NJa(cpχ^aڞ4|)g)4 &MFw*pF\-8bex\dr:qxWO,}I^k%է?=ޱ^k[RK,pqErpMar̾c8'/ᠣe)F-νi/kζ/*jϯX>/i/5:7Ŀkfx[V3*}7KMFPP@|L}?G5*63U= Fg0_H9ɍx'?]׳+Ÿ+??(?Rkn/gö(k}ST ~O=&ĝBHm_C.8Mf-{F](Ix6 tRX|YS8Qu(VIJ&ѥ,Vc~e(\&a3a8<&aOR)`g+Ia9x{7*|o}ᶹhW Nhj?/<)n񞪞2/Ο2J d 54aL1 9w5ZtgJ?sS Ryje.?Yaf[-2|/  2*T||z9# O asZ>NT9zxgŝs߲Gr^/.xA7o߳ܲ}Wլ(<[4<EXtKc^uMῶj7^3U*2_FI)QCJJ9>GԱT/s\6Y*/:<1zS8nQPx ƴ0\?SOׅJ8S_x^'5gtm5E2>V-#$D,oi$v!:s%A>T!J:)Rp*Tp)(ҡNJ1B:t(4 f&򼺌ha08l B 䥖g/GzԓjUVuq)Ԝ*# (_[?g_1[8l?xO9?dkN{ž+b770gnq<5ʤZƛעi;_1᭟ݗj-5+VgJ0Z6y/Zz^ ɿc?fgߑ$MAuYw2D$u1U`0E"hzm];'Jw*^<ϕ{f+5xI+)H?^ (>nӟ<M7M^Ʒ1O-(nƪm^}BmыX t$ wqvUr3븙֣ R֭Rtrp|d'K/Zs8ܣ&٦ej2nFyv*^X_*~5We5:w{?w{HDj? bm][G|! þyj_k6z\Z͆ /'x< X>qa ގu2Q{jΨbc:\,/ʱll` R XW:Y|Kڜ`#U,/ O _ζ?_1V87q3RJ5y_-4|>7Om{WGỻ}WOt([ʖOmqdu 2Yob%V]G8쭌a*N?Ft^Ty89]p' bt]iΰ4L>>^Np9S/cC<-zU œo$g*uۆ5iK_`'5i6~E㻓KiR_nu+[i<\)BoqU mQ3iRQJ:Y8|U(B)e&_ߊC2ṵ9_`pJQ9lOުY r燫BoQST#|$ou_| 4Ӭ+ź.]/fYQ\:qq+ }` gCB_0T~u*iթ^%,Mh:xZ|3## ܷ<>/C 儣BLZ+Qaʶ-Ja:ؙrTO/'|%gMگ8C uօmu&|wexNu.6)}Jahdt^#(Se0T9QhexYKC2X jq_gk5C T08[]S晞cֆyfUKN8~C? (?m?5ZO-R Lt~Wx<:?v~Wڟ J 3,.d_XiKVN6İaiVs e•b <iO9^?Y+]j8RG2q+iOc}35&'RQq 4xqľ.ϩYӾh_y9Í Ě뺖k:|AW~;]v]6Fe\-[7Pkdy |6"iK-aieX?$2ʖBU sV"&)ݿ"K5 /|q}?] cg<$5]$maeef|0V++RMӭjY)S >Y% K O` fo[O8&*a8.-fھ׍b;ػY^OϮ:V=W[AO#.+ A-׍)}iac>.-cԼneEk-Z>M04q89:4+n<&Yoj`/ц+ԱΓ᰸kp>x mgٶE%Za_3,bodC8)b*.Up#?ϋ^m*mW|u]SZ oXF;1f+˫;3K<؜$2su>Y?G@P@P( ( _to{%y<ϫ+ }{wedu =2k}.I%Nz؈ОUB aJPq|NZ3T!^xl7:oF DZkIVsbpnL<UFEnJ3gkv:V૟'Gm KMwI~)xpGSѮS-<_IT/vvpOdlqb5TևqʵzTF#C8ҬՆXV]—e9`8bC^sW4KYW!J2n8gW )"爎S i~߶?VG{: 0煡Vy_?O)\`R~x7ß_~5t?|EhF𿅾x ;uY<>.m5~][^<.pyIn? GڙezUkZ300jpUsCG0\ß( 0q^1ȳ %1Ikӧ)ףTp|ΥJ8*F8Le3~ʫA{?<X-~".$zssw+W`36rP$)HեS6YZ'NZJQ2S9{JWS4jWOz'ѩOC3RpZpWpUVOWZҋ!9Q82>k,Srn/FJq:XjjQ)5 )¬"(> |j#eCm?ŗ.s-I4x9夲mjLmJxڔcG/i5w9T8U#IrJ~kJ )W̳:ʥ8c1ٍ)TJqRSQePs9PE7]'Nޗjk-B-k٭cw7q[{-1$+Y3䑴Ny.^hZ9^gR)catG}AK2)s+C.,9\N5V:x֛\췣^{jP^Z_w֚}^ŝ[KIwo:$Y*BjhjaR2RU~ڧU~.ksJ5&O&%E85[5D칬{yGxP@)Y|$?1]i |("YE宔ŭ;8o.m=8|pNx\v%RUĨj.եGs%NUeIKIryvXqF:~/bs Su9(pו8riQC\?bo:+?sҼ?B|QƞiMe'y-[4V7loMD"k*WdXN1\m^ bZqF, m S 9b,<(5cRj5T?3LnYuĸe|@S:-gcE>76ˣd_xkjzV2p2U kR^“j)֤f[ùcc%5㰔+7NKBZjEEל _>>"ÕgM[eo 1yenv;b;9WZxVGs楤Cb]G MB;ZqSgu ٝl1h8PNZ}j~jӡJ_=exwj_eLUM8wbիƯHOXi֭'k#g_keE?>B&^/i#uQT73]EhkX~;tx #7ƾ/JLY03UcX*UpxXU9ҕZu$Ư.xW)q5|9 (dٗ\ז9ZG_O:(}UMΛR%+1^G]e;mB дm:kFԒll |/i_ o|Ӽ3ˠ]Tm{6}6MY/-\FWYϸ;*jrJ|V_]R QSU<'Md0\\frvqZ僌_73w-N?2詥՗ۻuŤk־l5)[VQJUZ3J1FF\iҚҩ8F5gNawF|u (P:N'6]ShޝI'M2r%NS}⿳WƏC_/~P3OF4^":t8k]nJxMӵV *!u }ԯ6]͈beV].ERJ:2n?UT}bm:xxQ|sU5RL4(>xڟe:Z}yr<# ?xOhOY1k=[Ec [Z66G-Zk ϯN.8Jf*Vuw.JX|fJrT SJz#>=H}(Vӗ;REJZSsdnT)#cw: _υ!o5 h-_1 3V^Oo"|֬3 niQFa:Rq%,l5⽃nSTU' EJNSSr Vu# \Ӕm'Q^4ER.:T|#$)| 5xw?~_\ο#gunڏĺ^}bM>-+1"/ՍL1:3qK7k Bk,#2T8U)~Tn剧9TqPɋ-e0xDF8G FѨ1*'(T|J~u?gO|-1_$ZώCIKFsoOlc:V[JY+b#gUStcVo% N$m\> MV(ʶoFcBR*SnieU:n<VtԼCZ*ڔe3 +9jv֭{H:cZىnDG d|/f3)%,CdtjBuzaJ0ΝXr֍/xc2Ys+หO<23UXҾaF,,0|EfN51~R)|oxWfmBWPWޣje6w~"uɧ9Κ5WPM4 3C~ BJ8-Օ?c,E,/eN*b5(*գFueJg)^\%T\]ceNNṯBG n -\T+J֣BgJ8G {PxB>/2Yn"ѯȞ+~ ԺmYRRV F<6VcV/2+VPS5:ʵ}'#<5H99Ɨ0~)GK}zX3*YjUby~ ae Np2#l( ( ted |nNj5~L/t -7u}i{ =&kvC/=:YFv솫ca[,a̸{0T 9N">Z'+t?c~ c^&bieK*}IQ 8xٍ*(0֕Z7¿?=G[ş 64tg KQKE筴M7S4.Txj*Tؚu0XFX)PƝ*!S'()(3*L |=-6\%k{f_][N~ҿ>":[~>=;_<{mxƾ)_E< &#H:Uީq Ҧ*pLv:fdyF'Ī=\VmfeOW &V*4q1:bc &GĜKQyvS;_,8<y. ŪsXfOObjӌ=G g_ſٻ7Ǟ81Y1cEg /ٝ*8,-&ӥIѹ[Vp83S ҫZUxjuF9QSsT;a(3,2#ü)b0*Xj7S0Ju)qRnQ(u|*_[=ᯊf ? M j>Ѵ ~(G'}Z}].)m,/f4VgQӞ1Ubo*a SuBPJ 3꿬Qs0C!_ey lRh0t Al;ҍg*0xzܟm'@PngwO 6J+/ Ckif _rkWןf+8[9>?M`}abTh<>L;ZZSJjOQ6& ~oG%XlU|&iRr^g^BsQҌPRNsy,_O>8Ծ |Vi xƟ5:ti~^7RZEƯwk4WQ\q1'd5&3* =j5J9c3LN*iQ^ҍuJ^1*KМ*q߆ . ◙`S1աN_WXzlN&()a:Q-&Oi;#B?WM6@{~Ө\xwB۩ZLlc3\˒ `TMan|BSUM8B?Ar,39f4018\4Ҩ`S%*z~l+xu#>9|Y?iaNmǑqi4nuد|9XĒ]^ZjVe=בpa0},ɛ`0XfX8lW5(jԕ%`R+IT)˓^qW 6[p2v9#RPR:TkP)֝ZNkQ¬UketpQ*!㿵7aZ~Z?|b|5~~x‹\ҵ~o!.x[Gk t4%vOE{-G%?RZ!xZٞkaq,˱?\WVF\^xJTk֞xW0+K0XL [N2*e<}|&gjMc㿈^X|"C/5X5o gSt˘ kCq}iJv76qFK8{w{[csL-QQ _E'>ʙf[SrR*L>]B(VJ'V:kƦ":tkbeG SG ^Rww0ٖyҡAeX2 3,- .L>1Xq0IF| am[ַڑ=O|)&4S4-%y%ktK2e;~8 aaX8UjUa`q(zJe:RI'cO# QN+TqUFqW^8ڔa7)„uJ')N#&lZ  k6f[ g %@< TTR,S:䋗-8+Vb&⹤tҼQWvoDVKWm_|B?'~̿~῀ -"oS' xe/H.lYaM/kQ?xƴZk崪*&m5iS:j5y(ϖe xX$tvUtϛj񊴧Hw'zt?GՌ>(x7Wo=JOCxnWM;5mf1]nٱU|&' XCbq8\5*RVS*VA8ӨQѫJ\`XT(וL-/P^IƝ:U*ӶT)J.%MK2G~_hO^D ?IxG4xTzu_'چ1{O&M/ScowcI`05&%ehS^ʿҝh}S)ׂg7N4s:1cɄS4M''OA ;:_?<l5صKVGmnՒbk&WYϸ;*jrJ|V_]R QSU<'Y(`sL<%WF(ݪrm`kr~k~Sq̺*ikue{ᾷ]F;1i6MJ}*էeҴuVRjqfQ79ї-Zt4NYӭ]џ/BrJ'N*SI͵zWnTaZ7RIrq Si~oUOwXq:Gm"ra)e[L 2KC]OvӪ)rFTedԾ O/SRk*ӝ>mW|IJ1S]҅4wtMCuׄ)Ɣe8rOr Ha@P@+~_6 ~;|LgOO{C{{auYZޗNq$ 8SvY'e!QGTdCXfc**`LاO)BU1pQQJxzYͳT,O' ZTFTĪ2^ %._]c,r3GE 9Vh׭b'qy~_OG ̳,7q/7 ~S oª1.o'[,r"|RὍL=Y֕g q8rr>~8~_ ~'^,QW/⟊?O 14OR#\W+}-A/q)x@T漳LF"*K)}Rn_+S|*Uܾ#Y5nypم?exZq:*RxfUe,[',])M'|r~xKT?fo[k(xVuB\K}76\Zk[]FGWSb1/^C5|/05 NO K:^"i`]Iap1pw?22nyKpotcPl/BJ_&入TG0B7S?ۋ4~c/񞩮xƞ ڤ:ǏA MӴHjt"mOφQ-s?UnMM/}RjY}?qX(Bq1+'O2N.Xex<,ZOxrq ˰x X\&ebqUêUTʥSVhK|M7oW>Ư>/OnMG_;eQCq<[=ņmV''|X8OΌ0Yӓ XUNlDp8 o3,f_y Y, m,'e&OݩV*0~'N J xcúŸ,OsͭVְ<%,):W5ӯr8\fWW:^u冧V<&|]U:~V\JoŹncVY|7ɳ,&p#0bpTjQb UJUcF׏߿?O >K?χeƫOZχ4+*w= .D2U[VtHӍ<:gYa4p.j]Nfg=LrlXW(P֥jbyy2^s iMRRJJǧ1P-Jt:R{k쮯MQ[H$,` =3*.+ V"8L6'*uG B"Tp*bq5cF:xl5(ʮ"\hХTQƜ"(]8:)RI u&ӋyTFݻ$~|IS,YsG.,QUrª.4q\$C%93=8 WY+7̪Tqnl>'ó8jxӭWNO*p÷W xxx牾%xϏa]{o<)|:f :MޅAmkżB;CB}Ng]+8NRXZ+э*TU%*<4TkhN<ښ .a>3Vʫͨқq:7Nu=ԇSI{Ѓc~(F W2Dž#.4]OLxڍ\B7V]BWS_Ø<ڮ̧1 JnSq\>Rj8\DUN8WgMG8;.b&G5h,3 cdܔcPYN**Xz}ҧh``Mb'ǟ~*|i?+~]࿇ n3ӷiVG >KMCU.5m*Q[H,t2yV7勫晖a*}ˆ q2-BZfn*ZJzG<4> N#3 Ӈ?e|6X̱8sCP7 B RP:Q|k ϣh<7|V[4R-/_n/%H%}knM2yn,ݺx)US*6_1+ʟ=(gvm%U V٪)8M0 mXfKJuP>](PQg501<thk€ (>V3m>v)'ŸLIֵ./ IqwnfO B|V ̱!hUT*1ORRb(F'Z'ˉ(|_f1xՎ%˫XOԍaeU<Le\>Jxg2o_ ~%||/K|]t!׾ Y7gOѢ6rl=Coh/>[ eYOS 1/ZfYoO_)aBnʧ:߅Uq=b2\!.'N66X?cE*I{z*Gq}M=_w xK!C_!g?76_e լ *KʫH?gWCWEb\<ؼ& 2 q}89,´2,W gU&~ bR燜axƥ WtCyKN/k¿s4+*b%KYS,- +˚qRSJ))l%Nm6өQrT)NU*IG8':q? "Iψ??j 'XQឩmv_ƶ!uM?54[%Ηi/pn>ǩ: iyVl]l>ih೬ ajGZR#({jVEF3ʜS%RpGngƼxke5K!PQَ\>"bթ&VN`o,[ooO^4o52uxS4aAz 6BLUu{VE8e5lnUX{Vu10a"|V'Nt> SNn%ex !R\֦/pf/Xl$B/NZ)ARV> CgOXxƝAq&yt;4]WV>/}ufX^G tb2.qpͰLN `%U8\vRޥ(<1U)UʿԱ\hUrs%c̙eus, q+PT'7Uês쾷!Z/şw3|6I |2~4xg|{ tύto;Xlt\[@-m`Yt.|m/r509vWb3_aG:ЯFXוJmN'_ V#[K ٖ+3̻(rc!}W.xX|C`pt7XFZ8lU:t:π5^$;㿀rx ▁}{Cvuw:n}F[h/.f6|&˰،[$ʨWYG:Q祘awVZtsi{<UR4rN;( \ OpyGYcq>uC/2-Q< M6f>> |C?kgZMIxx7#)K.t;Siak^͵:.?_EMy5[冊_9lº12k嵱x\f*c:Sh׌QPX:ҭ+;q.Cc2ʑv C2eJ_eN1b:U#)Pb^wS_h'Qo5w[}3:u⏆>ׁ=xo:χӭlEӅݖ}P d)53.9E/dQJ514+ήqV^#WJY'lO#s0zGOùnU#NT ʜᰔXuB Ƥ!SМ~|g"?m:}#Ɠ| cAu{O#L+7VhAc{׶'79U~#|{,>:ooW-N8/vx, ҋS(EN9 4(֥<kpG 'R8L]1pʋ<_^^{ZGO:^ >4 ?j |Gwúa+9N]OKּoy?]ԮtZufQ4훋#iM\5'q^/ў_ข,])F*y>. tNYMVˣWejzXߝ|;Kp2̓7˲|&[ȫٮYrx~3–&Zs̱8 X}.}N"8~2_?Ml~ {<Ԟ宴6"-@+^XŤ-"K$f9,rv*0xlkמټN OO 1Ա9h`*`>w/ ez9_SfVJX%,ZT+T^70U!:%|x م  _߳|GƟ"_c?5Kf_$q5եNx*G:9 |늸{j`?S`$2`U㧕 45*Yf OR1 J?79,+8sx,}' 8j1^qwZ0' 8DjNxw[U+P (`O'_Kx/S*:!<;>^&dW`!\f.8,;N*U\=/gVbb)a5BgVTJC 8ӧ9*MRlN&P TV8j1 ԯXl=4+ΝjS~LR+ڍe5o|h|@55տßgx̰<#a;2+8zl6噼0E8U<ͬM ·Ⱦ }'c3M[;r0Εj10hʞ"l [:xVTFpԏp >1a2m)帼V+ C,&1To0ХBZJ"?c"s_ xZt/x{Դ x^I1:v4Ry6h *'K K 6=T3`l1T\X,MLIjP;/nYn Sq:51uyaL&WW T1ըJabo<5hfus3\n 5x1bl4ib/5qTҥ[PJ&Zxqoic$~ sK^-|.)q&ob~ cN[HtmUγm}e]Xr6KF71thW<&" /+Vs fp԰԰*`>yRU!K봧1eq1q0 `2\u<B*pJ5* U OoWV<7~-; -n!;MWJwC=^n5c\]*KwS6S̃)Ἶt*,N:<=ըCХ2K u\6az^iθJgu?}5ό(x[}P]^#eP;K{kU( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ntl-11.5.1/doc/flintrat.jpg0000644417616742025610000153071314064716023017262 0ustar gid-shoupvpug-gid-shoupvJFIFtExifMM*>F(iN8Photoshop 3.08BIM8BIM%ُ B~@ICC_PROFILE0ADBEmntrRGB XYZ  3;acspAPPLnone-ADBE cprt2desc0kwtptbkptrTRCgTRCbTRCrXYZgXYZbXYZtextCopyright 2000 Adobe Systems IncorporateddescAdobe RGB (1998)XYZ QXYZ curv3curv3curv3XYZ OXYZ 4,XYZ &1/ }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzCC ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (_7oOxOx{F>3na [Zږ\gtJ5-m-iDVjʵj8x*ӣR:"b+S'-JӣF V)91ӧR)S,h pJ}# t*&S6J:&Fi2hֵ{hnsy soYDrF 2|~,b?CƟ~|-0jVҵGKamgTh4[bQ5;ԶXPҸ4P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ i|Cx~5_x~-,up|b11ա,VRG [v)rPΆ6t`(幎g[*Wey#aQ3 VypUkW̥ 6?>#+h~^xOx.'Zl|e6O>!5{\ofˏۭgeZ$+d wSjBY)_pWqن^Γ WǼTR"XV T'%KS1yw:8g932hV e8<<0P?gO|g'Y6[F^x3TşR_;Þ\֏#AK4XY1^vz^.ҧ$Uq`xub3.*_-f9n'po"'F[$V՜>էG ^N6OI癶pW ף *mŐcZXΞ"7 :15rొi?ho |+Ѵ__os{B<Ǟk {^λw&i:^lV" A;^ab q5l^*UgKY!=UhV``UYbZT˰n,a^09~p꟱aW7S ]K" mU,4UZw#>1R_g>I>ω<]kW{T _ƾ/..miee3^ yZ5>CU*ƽ_eُG F,e<\,F;} NRsZ|=7/pfaIu%RzUFIMT*tp<6-?E7>~MX?mg~!񝕦υe㟌ڇoM;ĒxWe UHe.g/Q1,N#O,<2/͟P ~Kj'z~_:_Kş[@ |0qi&r|83/|  >$uO xP4 TY7.p9aT`bx[1p96>3UK6S:pXڸ\(/l|3 O`kaKs&3 nr8c!FTTq FU#uV2^| <~dІ3. XFk L/NԴ zK?&<7C ˨_IhYsi,rm$R7ecWҥ[O180x4q*|Tpؚt8uW)´'V98XӍx..:N;ѥZtʽX=ztk4zQ_eu3\/*Ưן'e&k^9,nS/ǿw-<= wtKGZ|xn-c^%^2? Tq8Zr 3+7ʱ<9K=ih'PL[u(b09}b0X|w b!?c#O&0tg*2Z_[ጺ2dꐧl&cx<kf!ak᳼3nWiKs|U+(p٘~?<=@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@Iu? 'g#fj:v%Px$o hz ;eafoØ<^b> q[p?ȳIѭlj8Uc5geiWf8/,/ i_ <}[Z։}n GۣBϮ.?0j+c!bqzZTW Q`~Э9%rp/`^jx 6/PRt0ᰘ:Uᆥ=)ҕ dTiПQQujT# BjO,?ÿ+OXiVo Zx<9i~e7H x?H/x~ -o ԵJ\]zyU  [)U|87cNX0yo08 ,(`ir깖:J*SqrgQ{ȱ+G aro,*j$5?:^{M{a9d%_ ^8چ"yOp xFǼ40*c[1y/az*d17 O1M_'R>{ %\V8<}8a gX\V# o {-\_oO+տgK xKhuO^-#$O|⏁~ >!Ě./f =cF%ֲ9"2ʘLO f9&s#:ʩfتxRbW e򭏆aXl l>)`2Nyaa.YgLd(ʞ[Uy;JpquΪTπW7G hZ gW5'W;o N x? Դ{⾡D/ *<k[*#aiv.9,v.!Rc0?G>{Sڹv]q6/ ʶ{Ƭ"8O fa+Ўz0|\ W @?f(_/ڷ?Nl |oKn~ $7SHnZiE=^ f?çxcPϊr*ay%"3X*ѡ¬3)*8|\\.*|ʶUΎ&pʱ9U.qW1ֆX(rm2j5pgSE*x#}N@ž0񇇼]NNuiuy_o|m^8%x >$]+Z_᪓8SAC=epT7V')g?m_$IqN F0ϳ,FKlD'qDi>&LFTK|1VfXR̈́x㧕T"zY>S,-|6wa9€ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?o;u_OS↩j;}]5FY>*{FӢ{ƖM:9:>#+0e+J:Xx}J(Ub<$f>":t0K~2X'b҆Sq3pUzЍh3# yWiF42үK/\'?iٻоxŧšOcM | !uSx]/-VVmχ_noxw:嶵&r//چ*#(`iCJI jPyUWbbdrGx{4ʫ{|= =l `J &ei]\aQBYI*iI5̨`rVq6_9;f_!\|Z|Hw6qu>xƷ7:js[&e}NKƸ䔯xigYY~_qx 4ЎzҩNᯇä|;?FɰYZ)Ib/,:qXŅ(a/1JVjT#OlMc?5 Os⇁==[߈SXiN zQ$?;-Ap4tCq&[ᢰنPP"a?ZX(N5!Y,E9CUd~s'T|00˫NUpx'x=I:u<67gF8lV#Vt{'?)wtO!ψ.>#7? e^l~|u2bٛ84?<5Z|Gx";+ӣ]w:6NP[hD$VHsN/ynQ9=LxeFt8#NgXB8`1nM:'ORc9pX^g[ͰY< q|K92Բp:㫪lGͳGVl#~ɾ> ~ oW|m&| ߊ!S/6s(&fY# ,I&76S)0pr-p'Ֆ%˲ VxgZE#($$LW7Q10Zxz?K ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (_w?xNǾ2<}o^4>~&ҴK–W7~"`-_JҭI J&C*̧SW5uOҖ=vTa9r^O| cc嘜sµH`054񲧆N8\C9mL-n2oBx|uS3+!lMex n% ֜?|+2 bҕpUo'{7[q{uV["h~КΟx?O|b loC?hײ-_N_85/ wFehު>'ƒ jMח屩!ђVK^woCP^qpTpG>} d'6eE*|Iwߍ^ 5gÞ)Q|P7g|; k )YMxSGa)iJrZ<0Qa1X,_ '$3,Vg3o8O&_W3~fog+\]/uGe}oTztwv GFվ2i"+mHDTuw-#G'{|Z·pW`l (G 3-ɸ{W{jTg8y |>,y '50Ҏ/x>U]BңgUq8uu[ ZYh YO7¿_! DW9[*eߎE~*_I<>#n{t|/4z.ςa%ⷆvYB "r "ܺwp8Zob*U9u3J5mK:aqEbӉ3_w`%<&Q7:v_j OHvP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( (?SW?_|Ҿ4}oCEa7ľ4τ~8r5BUc]ty.tg{êit7~uXbXlM.l֮KeV} ʸ^)Ռ|UΡ)GV S OoG U}g,4e)2 qT1MaⰼJ<\{>2k7e?iO߃Ww~:W|yO%>վ|.+M+}xA7m:'Qx.<:f>^"gU153 NW¼/c,#V)]_-b3,>G,VuR2,fhᆌ)`KF**ps?I/?XIyyrrRgRֵϏ?u?/u]6{ej :<n`ů(e5Kl5=+K>xyW,W?>h9 ɪzd]]lJ1[St*AѡR)J\N/R FqJ+ו:/[ Uq/Aֆ"j k F5U9Ռ8|7&V*ңIJRW%5~;|b?_U  s῁_?q8#ek)xĞ/$*jqjzt}V;;8'2xzGh SYO y^6|Ë1Y*uCόs_eZ*RC`Vuj ,JG UˈK i1O!9RKTs%7WsG ~9|^ӿ`(GZ Bs2u-_!Eƫ r&ub%0^+E.UdeԖ:^ueQp0|,5gSRySWNG9!J W&N/ӣeSx9ncZr&"2OXlx:ਿ}i:>( cYﵽZT𵮷 /7g&0ts\:x'(8*XZ#˰ҭ O//R6eX,ï,8L^oecٶ[<xk]^^m_[a9T26/()ʝGVJ yvUsngGC uGF&Xqx l=| zp͸*晾cS*Oe,]LDeSLfMTjFan3=jf6c ă^?~9D_O,Ҽ3-P`k}= \?_>1z `cٽ:sJ?ҥ&GNxj88βl,ϊsbLʕJ8[#'Z/P:41h`ax#ʌf2KKXV+b[JNXzVaTGN6-;'_ؓ1_F_Dyi/ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?O&ൿYOo?4[_'@u<5oχL񧉼u8;> t}KF5<= ۍ3si/rT9+t%N'jQ|L0 \e`,N0Z&qz5)%~STsWRG 4>`e\xR?h ?W~(=a(*tM+PcdWŞ/ďU 5{vV6^8bffc9o ^ < 5¶q[SJ7)ȱO}B;hۨƕYĪiFxʟJUYSa]GQ{9kQj9T~Ub*zqSVjץJHԯKBUcR4*ՅծU?#߲_A<^ ?Y|Uܶ V 7&;]x#UM?z-hWRVgn G (gxCWp\ `沬tcbgRR&'OWlq^I|1_Uj./'Kia0ZC*pxkjVe8,> vmtqn; Kx3> O9x '*԰,<exar,T%$?/؃??"]sD/?fMe42]ER4^•,ƥh\U:1Zt3,vP?Kُ:l~Q@E{H ϋφ~ |9e<׋-Z}CwE~Uk;cO8C)bukԯ0qeY.1yp0z[4pjbh5G ? V^[0ק ۈi9<"_.RFU1TdUFf_' ~?֭Gof?O-/䐫XZc^JUq XӥF,f9bbjus(Ҭ N·:J؏dVxe|^'<1le?#޹fOZ?V|iR4KZ:ֳ:Csay:s}o?x,\g18e:NIʫ*5eZ8ژ\[:ӫWܙp+0Tx=\WΪqY̡:U<>Q QCB/ I/G]#xolOt_߉>ECo/o.߈+:j }-{@5W; ӯN4asaq|-*_`p8,tqt熣ce_7li& 1YV/$̩T0WԚ721-*8L7%4(εG 0Rcg]bha0ZWSiSӫZPIN { A GB MNv)EJ-J2JQ4OkTr{O~k?ß^1ׯHl_ xKGZY8 Uc`k3(Yv;2FJ8-lLP>qجDhᨦZJtM^]3,)st藺m<^jY"`vqkh%^noFaR|SὊ㱘*00x֯^*uaeYuL1ePY=AI𿋼|be__}Z8 (|__jot]R-jQPTIe\11SWoxa)ߖ2,\+F:NF+W'V׋<+=1u+G5o k:v<̉oV=˾11u2Ei(N*.QTR]t#58FQiI^GkIA@P@P@P@P@P@Bᖛ|'^)}c]./ x_k6[ƣiօ[73ih'IWʛ^֨7Tk?RQƥJeB_P§%t JIأQ.mm#VcG3 *e8AJq傔sM'e{$]5)FRqd,n4*JKe 4moZޑ-KYgiwjQOuVIgV:m*Sq$Jϥ4'[ӳnMP@P@P@P@P@VK;];Mӭn/ BK+H^{˻ k[h#y.&8aIQY'R*g t๧9BRIwoиSY8NJ)ӄ\9ɥB)6cvJ퉧jZfimj:}77ťouiuo$s\$ ;#+6NtBTS8N.(N2(ԢVv' Js8Bp'FQZwM;5yygZ\V66pKuy{yw/s{T/U*PP+/XzÏ.Nj~9~gO)پ{ ?4?jV"Oi^QwZAop`>pDžpKJIQ00쳚yUn%a# ngS X\Iet~ڄ_ *g*Z0FtԔ?`n?Ե /3Owjv<Gu}{s$6ZN ;i#ffTJγ+9osWc3RJn"U*8 U+WkrQJ3^HQ Ԝ!/'"a\?a_pf]JJ0Іt9 TNNNE ῀.1 ~|O|}?A{mg?xI<;VZ}ky 7vq2ż2ExN_,63VT14&)RiAOe$==UR=gB\f(ʝZs$v]rP@P@P@P@P~ο<=:h-Ǎ>9_ aŞOZwhehvݼZU5 !ؤ+xo gV'F1YŸ,kTUJ*N9zyV3_*bO,g1>#!5hԖ 8\',+9)Jz']G~ l..?iJ}I&oҼOEZ9Ӿ2|kK2H%~x=g˨Z@Yd2=,ώ2fGV;l5ex//O'5*>œ . <4t!N{f8_gx"Xl1>ڔ39yy^'rJZ aiCOx.toS]Oi:߇GNZuSMm_MO4Bhnong9HBL>&\>":+ӝԧREkd]NjbaRPjUTZ5#5:ܡ8m}djP@P@P@P@P@|sW/QGoi_|7x +_vC|[x3QI?OkSB42?iMQ֯0K [ *+ʤh0f*U kTSѥ.УV!R*wB:jc)aQKZz^4*P=ߊ\]rdԵ RԮ Bj7~䯙su)i&CxAThѡS.<|5pPJ V?_˖']#Omzx\$bUVjU#NjWV\?*S( ( ( ( ( (Zl/ٯg5=xK\)?dO |BG>"|D|/'گnzֻ^^|;-iSj:n,9S1t)4+ap=5U1XϏ)O?೟KO=+I m/s^n¿|}# |ik?]7'EMgWlXżNggf%9\sjx3˱ 7Jhbq{.9|]> t6Ubx㇪b(KN|`2V\O<O*xS1~e(G1/2[_[_ ( ( ( ( (?7>)xm ?o /~wx uٯ׾_'kxO_;Ǿ"ҵMYm7,c^b~Bۃ ̥P|f-ӌ+B,$ɲZgkچ<'5R:kp>+A(`qOv:u0TgԫbeXjׯRtkbrzpƖ5W5x:T4y;s5q8|2q*xLb03T+NB(( ( ( ( ( (UdnU~Z3q?|`|94xA_ Ï3ڷl*R'ZG5+[h%ZqN9:)5+D?3)Vʕ&+(?2|`_R PGוiVƸsXlm87bSF%FK*y&+ Rq5 x:Qp2jX>C ]|\o Xe\ ( ( ( ( ( ( ( ($$LW7Q10Zxz?K???}+JoCĿ $SĿ|L_ |e|-o]ocP}7NxVLWWImmNd9opT?`8-S5Yml*c2 |l>2,>|Uҡ6lgB!Sa^>ʝ\ q9 Ty^`X(ƵZӧOW~?hK>K> 㿊Ekb4?O@ԍ<#%X5FYn ]X᥅&UgJҥ t1?[Īti֩,U%Y׫G53B#2/KO 4jQBZ1e:tjPex4<-,>&XTgi#(}[+~ _N<ך|A࿃!I>o:L-{+\s0J> Xڴie>=,r[oeB=*SF287` Y[ Y)a8rxLg{HX[878cuu<U5_N\o3F\UxT˲\}lP*qoեK2W/s*YG?Qc }x7_%?pO,V|qOTK36,€ ( ( ( ( ( AoO gKfڻWs?|G>&@G6Y>x> x+-vxE-I?H~×N<8Sø،8lIP]9USң(PVuU:Qu#-LDGׯB%Vy,j]x1~_S^[(VcpU |}؟w/z=o -ƪ5&|;SD}~:oĺތWwӵ9IuK[XuKǖu9$**1Ɣ8{ES%TJ~E7Yʷ%R+r{ .rB ODcNa2u=~4[lo*w_ }Rq=i?Lo^ǨGoxMw.mxF{M.G[2YJpa6NcxVpG:Nȸ_x2YOfQsV.T} 8 n!e9I!,4O+q/,˩ѧK)8{Q!:N"ܫJ#C Jcwk6~߶֟wN~?Guχ^??9@Ϳ_oxϿxg;2FLUP@P@P@P@P@P~ҿ_/+֕'Ms>%Y܀ih6xzŖ i6zψCO;xXhQ_ֆAUڪNE^J:]l>#6x:Tbk7>\Tלc9(E0)u֝,6lMj4g~_glk\*l)4?% >,G.h~,DOծ7oxPåOCľo. jpu8bx˪C &~+ rQfUhաZ 9oW>{% pp׳̣[QG0c:pY^_O˥NӞaC*ɰWf\WQW)P@P@P@P@P@ZAd?R_?kz/Oxwc /]?4Ru5/Ub[iz-E\7ebxTaeհ.8Kh+ʜμCtu,"w xw Uc|S|E,v_UqaFs˱8[O%-~| ds'bs<\__%/G7?ZoZXDx{\ ZW5 ͬx'\i]Fo?f&ii`1q\+8G0x[# )ybOG\pJ* 8ʑ0Oi,(QbgNt'fN1Ԥc*hԡ:4hUtaWqXP@P@P@P@P@P@;YiOxKf٣?+Mhߏ^};^!ѭf&v3IkޣxV.Gɫ2|'[,q^ 0JPbrc,/gZUG(P1t1{y*^Ka:F+H66a[_Te ,aZe]O1`>}Rx ?fw ߍljoķ6zΫ*/6ߎB'Q3\6 3 :Ti}W x)q0quue^q48*l^O e,,ׁ?iǟGQ ٝ<_x'#]Ox H{)*'~ ~*jൟ26&V|B +]#U_ j}x xsUρN[h[ q{Ia%wPtjfka2 u Aᰩb͊]qo uZ)Ogbs,_,8pU8\DU.|wc'VT>gG *RPu2X~=V Ub'x֨cSp_fU[ʕZN)R1mP@P@P@( ( ( ( ( ($$LW7Q10Zxz?K c%~ߴ7SimFCwkVk5#oq;$kW4$ږk .$b62\P0]|S=on|[ E$t dxCJ5:cC% > ((0XHO:<6_09VC OOBg':U`quiYG0ؼB9ighRoѪx kUV]J|N Gx|,~̶>$|xB| j^3|s3v xJ::?__ "xWz7-/%w^Hml,7n_i4Ⲍ[ SO)ӣ*|E%J48L6SckVΗ`غ(V,>6uO$,, \4:0<%j8Vcl64h^P@P@P@P@P@Qk`c|m߇w7].KY~5x4Tm?5?}6;C‘2y{<5>71r$ S0akXuh`?2kƞ+B|L0 #/5Ϳe}> [WkBo|h/j7˨|D/kgKKHVBiS#gTx!`xs 'p** W3Y64;^VRO)cՖ{ĘWR5,LqO6&iUew]gJG"NN_p׍?oo~zG$7:do |rV,4nk^> xs] =|_5[Oh4/Yx]>g"a`,:3|6w%Uڔ1)bJ8gCcV_6K:8J1Qf+˦B&Iac3= Je`a5qu14rzdC>oݿ'WڏaOO*+7׼c|1Q[Ş/<3ռuxc7|'Kþ5.Yn5;o,4rS B#2Vk_4Uu!Vs }*eQӝ /"󔱕?:XNiS᰸, B*4QzuR?_8U` ( ( ( ( (_ںNՏM_/]|Mi_H)xK O iuC>$|شph^~; [0eO 嘜41P,V&*,E/{ *j3*6F$ҬKS BqX8K;X,8l^]Fc 01clkb+Ӗ+:βc(kҥ,5 ^/ZIN__\c96kf_s l.&8LJ827|+- ^m>x~Hּ!xc:u_+aqY̱.=Gjaj_QʱT УxAcR׫ӓӧYC EC1yV#ץ)PR3:Y*x<%Q /kBfUYf1]K|0j;~_(H[C'w[YsSzgoZأ񧇴 Egn3Z-kṛ_91x&ԯX̺hae؇IexjX|^o攳 ~1έt0{9qy$˫EV9S,~cqͰ|5a ߵsbϿע"=f/ugǚ>?3\cjve?no>d:UE,6]Wb8W21YG 9OF3yfWY",)i74NA׉[3YN;}y~{!W ij9apU2^o5ZwbYvPƷXR7򜲾Grlɲbq*̩}Y`eeB0CA7S0YRO똏|}d)w)F[Dž+?OEUIh<+ahw,F> Ndou?iz,?rRyaRCUY`K73:cj*aG3UTpr<'L [*Vbp9E*zx|4})eye6zzJ ,6%fjo~JAg ߄Zěk[j-Nx& BDž:ƃvu|'(dx|R|WqM . d!L+bTs 3Ɔ?% +lvq,+N^ks`j҅L6+ԆcNJ,5e*UVWR yvaW?~3` ( ( ( ( ( ( ( ($$LW7Q10Zxz?K ~^:|-3<=#?O?OAs|YA}_ 4{m/QӮG~(i_YF@mIo}Y)0<[|GuGst0jP2*ԌvWSbJb.xµc8[*pg0nKZ.Jd5s/tqXj\a+Ƹ*UN:tH 8 ͻoVPIE(()(+$$KDZP@P@P@P@P@P[JfU?iߎuu⯊^2e?g+CӳI|Cn|C{mkKm(yY,bץr>#Яs-, UҎeXfinB3 㲽U~2O|?C2:Wp5 ZXxj8a1XZXj5H阅P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( (?9i/+'R!?h|IwDn|yNşn4T%ZtMBN >{i5kzG4pf|F31SJ3"(<Ү'?eh*P3J19`a%)~9ЌeWjbQhUpF)GN//=?#[ eo\.ozUc\Eq/ϤxWI1A1+i<,F+:L]^XZ82=|L(ja1+ U^^E,4`jU TO<Wakf68x5*aqXF..Ԣ1~>_?~'D{/_|FYxlx(gw\4vRk3WR'ԗL<Ye4ʩbcXbe*Ctg8Iќ\<1L ›GIb\SrRR# ם \<:R9^YP@q?>O#HY?ŏ_>)X)O z.jYi?2[d6F(?%,?l|~@?Fhr|AO MXxsð~<ޥs ؏{N\E Rkǂ$JTyMBkRo>UƟ=u*SFʭSiʭz|se>HTp 3,?l|~@gUýx&7ΡmOWkwv Q]}+cJVMlfɾpnqNU%J3wT(QY|4(j8P]㣣V4VPimSV/e{:eԹemsz??G~g߀^񯆯H |u<;~jV?%+VeK9Yq Re*}TjCP5ԇ<%x9GWN2pHT%8 r|JP4 Fi83)1 WPnm[Ǔd,qߍ֪| z<2“W:NU%F3B.h;Rr悩浍n;5U8֔%RmBrcQj#iO٩r]ssv_F$ >x3Z˩x_ bF.;_$R,7wrF njPj&zu]F+g)rJ񕤚9VIN0s S/=7iÝ&̗4U,?l|~Y8 aFg{=z?K5[?;3XѪ^qVzJ"ieaYe(ԼI#|X ; $M)J09()RJ1WrvI$vKWk '&)4z$mK_3}6Vumco H jz>6y56Kmn{9ŜqըTqt[ 9FQUƵ\;+7mB#+Z\拌+V/v F5QQS)ҚJu!gUýH8 aFg{=z4$?>3G OXOߏ7R8o|W ;$Ia,}n).mܥq4y^j5^jJ4T+F抝ܣR*QKUuѩFOJTcR"\QNpR#,?l|~Cv薭>j|I|)[PM"?ᠾ9ɥj /Cg!x&Hh:q'Yj8~Dd9cWe?iHu\~h$ZR唫wAFI}*?JG#=~!&M4IOTZ4~3XѪ^8 aFg{=z?K5[?;3XѪ^qVz4F>r '! ~*A ǿjrGWy>. +~usT3AׅV*RNR1e(5#x"*†o`rEJp >'b%F:Qu\=Z?=aE_wFH̶zI  S% ʒ|էjESJZ5#xU;7 (M+Mjw`3i3-qYPX%zX\vMΔRڔ:rg4y?&gg|S]kn5/~&?mXRաXfq O2qWaץV'>i51 7$pgMI;Ǚ;fYU{\*O JXƾ"0S^)T:svG{o<]O|yᛉ[ޞpm=|]mo턱}ʼ.xPa(ԧN9­R^VXr7J7*u*t)rԄӄ^[eʱL„gS ^eN*&Te(ϖQe,?l|~LgUý?%,?l|~@8 aFg{=zy?Ri֗Z/V6PKuy{yͭ4\e!bVYt4VwePMgZ=*էB(խZqJ#Jq"Ri. &ݒmJE}|;@~-q|amgԵM"xO*FQ>+y7qu][4){Y淖9ѩ F 2iEV pҚe\FFq:SI~_年+\ŽSZuMCHTvV6jscGqqgdoeC(U,cia(TbkT^ʌcFiU b]FՄ<5hbiʲKU1xܥJ8Tr5piVCZXe?G,?l|~]'yFO"<7,ë:n㾧'oekN[_[Ey!uY{K;kฉ0>?<^ 1XXb^&<^jb(B*Jq})F3!8ǎctxz;Ng_ TGEѩSdT媠RP:WK5[?;`Ìjw?נgUý?%,?l|~@8 aFg{=z#?oq{?xJqmmquq%ʼn/ [J%%;ʵks=- V>e:O,$deѩVqWq 5rYRUxq٦]Oa*Xx.CigkjMqq,pĊYTXbq8| ]zXl5֯^iRRn1[I]H'&(9JOk(9Idn3OZW~:}#:G?};Pnwi_Lo];ldB[ESY)*x6A2F=^Y(*ҒRJJ.85o-W[B8-X֡:Z0:rR0JJr:sӜ(]8 aFg{=zgiE~*|7ojSh ><|q4Ff~-.AJf㭘`0ج> aX8ZS. &K|^յT/.J4w躽5&dk⍼Ũcp1t044*c12qHNa*ŷ(BRu&ks6qx!BLFsҍiFaN0ҍITMΤ-ԒM&xt[H xZ^Oo.JZ-ȣie{q2BRcx qBstY9\(:!9S1=,N' 18|UaTB7ViB>z)ҧ8թ q>7?5g>=i?S\i>:̹Я+jɆ27)g1bhbyƍXN*|*SMԅ79 9MQG_ f˳04^XR:NRq,b5K5[?;Q3XѪ^qVzÌjw?נgUý?%5O$oEᯄ|K񅦣?]NJԯJ⼷6qY^OAt,imD–+_Q &cXzr穆J<+nƥlE(RU9eWqa9Ï0xjQ˰*8dѫ^iRPUQTNsU*ӄgUýnv o!ek%TR 2X_ $ZRZNsVݣN8r}#&%q.MF)I%vvI%mO-"}w%,}pߵ[94ՈsZ_iŢ+2ۖ9[,:0<3gASUu"TPUPOjM5 Y3,.uVxz)W1w*S9B|uyjiNqPg/Bu6\gG/φk la_[j0|V6/9n-$ 3]l.2ciԫf^V#R>k7Ⱈ<ֳ&.6xjeY1O[O|St5a>I%U'i)F>a QI ? |54MKARc@`}~OvIH_[k+er,)j%JcFGI5_Ы}:#5 N^lˈrRǼ+PNXM3/0Y?.`:"Tt+T啕+RM|QvÌjw?פv' 7ֹ3z6Z\jjimM5ml-GX%i$u@Ʊp:18E.yb15aB(^*Քi7isJQW&dݣ);+0cIݒl31Vu;8NiœgQƔKݦ3/eWOY[$o6)3T~=ذkxL dC4[ cVx,M \h7¬*K(t$)NU~Cqh0\I8l |o'X5^0ʟ$j{HarV9F!(N3~#ܿK5[?;I8 aFg{=z?K5[?;3XѪ^qVzÌjw?נ<$g>$[| >(]hw~%OLjl&/t>,I&l#lfk[hbجN3 N'B8m*rSQéVj񌽶# SoAW9B0 Oia<7 K2!R*zTի:æ>΍yB U :UCK5[?;As-.$| ox-Z|C?"tDR/ȵo\]M˷Y1.Y\ -BZ|H/KV(o[},n>ѧjv6ZdxT̲ReeR<1:jUJnNr6X^3,f*dʕjtW0JXs5𸪔XZܷ硉F9)B8N2N>' ~&鶋*[t~6_Z5ä s"T6EB7KdgT]fLUeFSYҡVsTW Ru ' _xC^kV;h:M%~X|SҴ-AgXկm.)XZ*u]V%hU'F)aVJqIM%|.;7a8^_О" q6s Rq*<\y6QJxG|Eٻ"iZ\({{7S=wsk4ȿ295J2ڌiqSx2֒L0.;KkǞ' ZzvV)S5um,ѭ3XѪ^qVzÌjw?נgUý?% E$gS>/7 h_㞓ps}_|\oUQ*͋ap4'WN*J˙A|U*^:PSRrP NQsJJժSF9֯^HQB4Rze ThӊsVN[F_$O/ >7_ݤxž'ӠnMON]]|SQ bGR0ʤM5RkݭCOKB:}a4\0fJXKXQЭSWVWJ6EM3XѪ^xoC~+ s<]_b]50թP'ᆧ?kZ1FhVrWXaN *n~ W;~ؾ8qv~=cq<*Wgo|nZ4Y2}oo{KwDυ<_  o+oUվ?|m "?x紞"y-dKS,;k .*S8*,\SR o9S(Ө/r rIKops\Fgq,6>3 &)b)Jaq⥈֡ QҌ37w{R(m]_B;voiP8}K÷?te{[eiUWJPiP U98PQSUirsrO/<5O fV."Z.Jxi8&R^ϖTog,?l|~[Ìjw?נgUý?%,?l|~@8 aFg{=z$oU|"?R?~ ]Ѵ?V/vnu[[ǂ񢽵[sm98 y,x:aj=^)΅9eE7:t\NE|ǟ?qVz?%~@ x"]/mfm? K=S%oX⬚.C,qgj66 qf)yT̚O38IUe <1 S_^ivƯsui.$+ ^emk oɎR&N8έjJtu*KHAEZR^ZT(P*ש 4(RVj*4Rd?- ^nj֟?h}^CL-*F +n".$]J (քե9SN_'(4՞s3 0hbpx8jZh*F;JM)$iggUýfteC 5Y+Zk +ZnrZ\"XEV{-O?Po#GY$-n2$ 5p,tbthկcFSzJ0эHFs!)JQsǏp^y7 {EIVץ:҄F9U=y•I…>j90j3(,V~7CKx3"V:Zey#+WWҒy!8$I zpb}g Z&**B8TiSqNjڛԎ<2Ljfi05x竆mWt((:4(x SIe]|:Qcs{NÇWf/ZYK)m~.Mby8ʙtXca*WOlULU*JrR 08ޚ'tfYLJ"X,+RRRp2MSq)Z.>8|w5 E<6Q"ĐJo/F[hyy6:8SΌG^Je),6&/RQB)Ved᧚}r_ О*="[ %VTJz5OU98 aFg{=z;gU6I6vI-[m$X?o7'4E1C|qJd3*i7^#宦daqt-D&F0YFTaU:qս$`iOVnN՝WZsÛq|] El./?ʨWVX|T'˃eqc7KUK^3)S i{*O!GdA|_A Fi>5$$$ziSO_3翈NO oK_o6%>:{GHKvL}qZ<3:]k)e[ȓX=yo;#^X?mㆨ{3'(%OBv/x{n߳Gr GFt?]#US}\d! ^6תuN*ZUa%u:uiNiTpNq(I3fjX&/ ^.TqjFRp%H9E2w(JҋQ,?l|~HqVzC7 #WŸ< Ok <"u?j:xI>)EEPE ( ( ( (?88oEEY%^k :@ cr$xsژ[7#oJ<>UmgVƹvm].&+42;JJ,/+os,t:3|d?gG d{xS%MƩkbڎ4$?hf.4<4g?_Ǿ*̫>'BHs fmflN# N8L *&ǁ :?qo|1 *EƸ&' V,kpxL>_ή4MaqB'[S?g |(][]Liq3M ~l2k^*>qexoE95 V,ypf*jq88L6k|r\ܔW)FcUia0؊`gEѡFV^X\Vc'EҥN|N" |f# %z)詨ڂi>',5/;{ų]AS#YdUi21ʱNe^_tfRx"7u)Kn1r噅 -\* ah{:ʆ7OEUy{:X,\ (8N|bO@N3U M)'M=ZZ:{l':53_<'>~~׵S>1vZCPIV0\3M̓tTx𔛆ƼImR χiQVn*ԥNXBu%)(ԚmyXud"*q9oW TF*U ʝBP?vSoctFUfELh`wTX dG&11ubqN Nѝ^[nnKoסpxb+ң=0M?'SGCiSƍsKͷ~4? G4e5`ۺ[}OѬb{ d8ڼV㫸51cx*+r(qrSԝ,F?8IF$85 n+KW |⚊~T"4]a(ԩ'UrP/ M{y<)eWl NV0ھ'h.eխd]>gA[-\q9nRKaiA跞aVpT"6T(xglFu8UxygN"5*hiVs歏kN) 9Ꮙw>|54GƟ$/i:|YͪYK=gU|Kx[H.gSPJ= d\U(aj_ZV1u*3 }^)QSͩ&L aRx|5 떟#nĺj~(寅௞4wb5<Oj%xsCqeKyɠCVS*[QЬ#{z)KX\'iQ4j8*َmӡFB5aǷ,do&{78gNl5 xӄnݡ J1WrvI+yǜ|QMOO|D5_ɨMG'$v}P~jWV ۔MN.sk+sNqSt&/(8KR.2kzt:)F!%^i|rZu6MT)J9S7$ ~Y~{_4k_x[ÒKM4[1Ӭm71@;W; $Vf9Tzԥm)M4VJӅ(EiB)^94q&QN!+ԭ:fۻU:99; ^'5|Y%ih~Ѵqn:KƸ )Q}b:էVV9ԟ, qĪye ccRlEzNixFmſjڏao\•RQ>pcY&'1eՍV5(T\rҔj>ګ}q⃮ ab W>I"qDg!OꁚfO#VNwf+*58sf_SVQ ⽒(ӎn=Oa/ֿ~C?Ǵ7[O~0)> ]~UuVѼAjw#}MBXյ /9?iЍ5ۨj[υ`F iP'Nœ\VrT(8L?8G=},.mq8ʹxiJORҫY*1AQN0|j'ncuq7- P׵k-.#q>i>34;N Ia&]k6>世axΤo0ӫ,F*Jr&NxEn#iU1/3r|W.x֝(ק*~q<=9OWd.0ke5q0X,oO' JGfYo0 PPO/ȿ?_?EK|[ƚYò\ *?EСHSv{K˔MJ8'?tr,t3f'04F0؊2 ,.6 76XY)({tQ0^],6icpﱫ yGfx.Ieڞ;/CFNg[.ɪVWu>VV–+_@~P@|R͟0S>3 WxO׉_|?nt3Wln.!xz3[j:{@b6˰8c6.Wu^&JqTIRcS"l- +k,F' aPJ:xz.(R%9sO(O'Jf?QbY5~s5~GĞ:mxWZ5e^o%Q^Y) %RO,heVeS皂VrGBӫW<>b*ҥ(TV*iSZ":l= r*ƖF+W/rs;F-Ϧs?ƿQ؃Sf:~_D?/:]k]+QQ<_,|c>ǩk}9c&<#٬iSdiCyTNr`8|>* \ )V#x=ˊjg fYWùF#JKcbX|NNcq:S,6Wjݯwl|1KCdymaĊ;k)ʧPqo F+vmp._ʼH?/C ,0ܹ)BUrj S,傴 ( m?Z.Z92GԢ.eeQ.l+ i+>B\:G*qjLBbiNXӫZGNyd^JUJԥV N2Iƣ' FqQjJI]mx՟[ݟ_')υ~n!|Mm_]m5k{{_]nZmPl*DQđ|fKR<4=<**Rq|a_'')NhСg)TRo,?xw' +e?a.8U\F/G Յ|V7Tb+WQ8$~ݟ~SB}⟊8|+|_ſSZy.4 j׀ZM#ğ=1nuk`6_u9 em.W3˳SJY7G<^"1KSyvEMΤjJUFs 3:XTOƧU% ~iN'O^*0FYNZj-Y:x?fgq‡6>>g`oY7V3qkOʾKռ{K}inx. +rMA|B䡺Ù]Gt\/P+{ߴ\||A㶇M$W{^G-> AۍR56#™VZRqY~ t0f2⥙cX1yĪN8|ޞ2̾N T0O+ #28C,ϱQO7f5P,,ژ<Î7pyL]f8Y/k<~//PPVx83mΎcXW'Zu'!@Pg_ߍ|i C _Fo4 PѵK[Kqm͠K8-/<C%sXPO/UT[UUpXN|=*ӝ,Sxzt%QTչ8{)hb*z(xu**8])OVO^uibP&K֊ARUɄ?}sg<LjЪLS獼G$o֬;_g𭵔? EdKmnMn^-:f!xbxVT0[q.n4pJjNzxz1JgMT"a_\tig_ta7W*^1N8ƿ  h>_iqc./!~szt|[Tm1k 6M-dԡf8R5i%Q(08zFyҥBxb(JFOf7eU(ʖg_͈^Jx`aKR N ZaVhO~t'=r/^hVH,4CV 2K-jӇ>#)B(zq*t1:^*q5+t Ƥ~bh>^DŽ?VZOziͬZB#MZe*_0!'bHWSiV8eUqf3b8xR# Ws7GFVVGJ+Q:fVZuc o ~_f +x[E~ _:ރWujƳjWMy{iw6oQZk~ 3i_BO8UW$ibW^[O8d9n#n8#TS挏%⊕?qM\fga8UWyu,,Ĭ"I³9Tu'3MNsN]|1_>'EU֟qVjY佹yF"yL63'Tc5V[%,$aB8hha*T>ø|.UO'=ܓJNXʊTZ*:TnxVU*g|3Ծ|fҾ |n|R~'ImYN5ƽkc]~ε:Z4qX*5 kyka O_x.+fUqdf\6iqUj}s0 .3&Ԏ(Qζ&K>~%|h ^]}kg^Ю^^VQie4otaCCJU3#2.&\+3qঢ珃Qic1QpsY+!:Tyn|G݌ZciÓ0xj쟦P@ROٳ྿?_O|K>KwZgy׺lz~ehO'R1 .CLS /<{a0aЧ8c z% ի:xZx,}zxXRhJ*'?3l=319oq=L !qLLpJpR5%V2xiaUP!`/2٫??og2H,5d}}P~~~?|#7I)PşfhC%CO {ZȺvmvKPxmtcf\e7CpTC-BU縺ythJ0tgTcxzx\wpG^>(c͸K+bʳW>|jE|*XLjQ rܲ*Uka1xb%O7N># Uѩ-3uˈ|?[U.cbn]1Yl7YR`EWajcqp_r~P@r><7%xKY?o|7 m/%|-hy4NIcWi~Ln PxlTjNFWaB+S~ V^URVt8K:ԡ^|=Noe_ YBu)MRiNZ3t% jSJVJ*F3?&w[ {!5?/5ME$5+CZu;BDY///o'IݾK‡O 0p#:>*tc*V_Z*Kޛ?rL"g0V8JxqVWZ51xF"jDPNuUIF?sOx'K_t};~>妙_[qce\3yH=sidO#:ʡᰙuz)`jg|;'Egn?4:oSO 4VQRO>nwCx_C1 2N<"fy6;xiիO F"ԥFHSRiUiBNfş,xONoxƚah>+_k%Z+Xc"kBhax{9 ᲘsLK*ȲRYmU QJbkRtp+T:c Sῇ9&SsLYNb1cs:J pB=*v*6 b4RR~ȿ 7NѴgǿ oL5h>kV|F}BS>S:槮kq^2kǤ5aC˜,n3K3(ҩfs:5k&TtWi0z–1s~Ð8*OK|1NLF]ҫZQXFRs;B40Xjү.~>9A߇(|F!C3\ͦ*kznkXdYG{gO'<WGqyU,vq:l`c'eW T+غ2O5N-z|>d8\Y帜g̱t8|CSB3c*SK)W(|=qE|Eswm_NѼ][?í;Wy՗z>kYFZj1pC]K}^˯"b0|5᱗XLn&4f<+:L-js]9K1RT*sp>m½73<uK Jv7Q j2U]@Pl/s􏇒֥i5Yj7f7IԢBkː5KL.Eft)Fm|^IF5$b!B5jΞ# c^ZEʭIx*s N[OSk⾭sfxlMIUx{UT!G LjO&j'a2_&[Y̬) "w_T?? h'_ş34dž>xW&x:akw>0Qh7kTVҖ-KQ$YQb uΔX<ZթN 2%8{*uq\֮.5cVi,UNzp ଻xcb V_F/hG;L3د`쪞 Pox:Xz?O~woZ?OEkvľ,?{ĺ$]s>[5]-SDnOdN78apYpCqYoq>TNTkԩBO 8cnL~': x<8,v}\*agoy3&-PêغӞkƴqQ/켻N,t'>%꿷H,x ρ$}qatŔol<7f4+=:Tu;V3TMb5f; żIXd14<$c%*g 8.\%jyO G2!:51*lL%LQL5lxHڼѡ<= ZZ򡆡k4q|Z| WQ狼(Tim_zƜq$:iINPxy(j Ⳋ.aԔ XjdcN5b ^3B9F" ,?2sqUNxLi[NR,jKR5jO4~W۟P@'ğC;u jM{ixM>+_/\. WpﶻILΤ(VijZ^ztjѓ!(0{VM+Y)pyGהo.NnXV,[f.uhdJ^YY?x_g*R*4ԙݿƩ*i sᏍltt-_C |O_g6ms}x/-3YUmNn5+MzvJ^\#ͳ2VTCUWC;Y9N#WR6 ?NWwügq0d7]hrOr\V7UcS ,6i+KJ~. )ைg VMo^'?tmc֮m#w*XZj% k=r Aq+>cէಉPa^JuԖi04+INL.M_,¼=GzԨU΅/OxC[2αYKN|G+˨Eӣ̰6}*&9)էYP@_UٳOo/ +cR_Htn|o _oQׅ<;%搿a} CRN>tH]e1XZ NwKשR".6XF&9'VThU.wEƗ$IC{)p8=Z hT:z%aa+8zѡJ4URoo*uAe5ٿGO@ >oc,oT;; _@O?'~ >9?i /| ]ֹiDZztqMu/\qSݍƟͧϥjW g8 xI`\O27˥&bdlUU/O-aIʱ1 ue⾫Ε\P XʘHO4O' uiW5}CWOß?P?%ޓ+ !_/6lx/^$Wuu^JѤ q]g*i7'E2jqgFrz<=_-ೌ# [.eؚmЭelneӣҫ΅.18l6iౕs 4kFr)`zlie}j`+GZX:sOm_4|@>ig &_OAfw:ϧjo2RD;)E2;b=yYGp/Ju#qS(aB'5J.48ӍYJiIҜ:FOZ0JVW#R%F;rmҡ)֜TcN {; oĖ% =T+|_Lc'!'4 Ӗ]N}xyp^RS،&*T4Zա~W~P@y_^uo}/S<85+mT~+o&xK[3 O{&uMդ,8*ҕh(TQ 5iJT."5h7My:>%SUCUjjXrbp-UJ|ԧR{'Ÿ?o_7/ Z}MKy62I$&I]99_3yۍ.6ڝ >mT0`:)ӣJ ݅8B(%^#r%,4&X59Iζ"Ze)JSVsm~W,i JGߋ<7Ul{{ؼ9Ū떶Fu{=[?3Lo<7>$*.ɲɬ6kG n?X1N.2U1<$ÛhSSׄS3 ^SOeQ(T0ev&'(BXMU\5JaQ3<>-?<|,na9Q2;2?:ŋVQCAk'L6KŹ~*T8s aE*pjmUcjS=KbN+xO*Wy.Q<掫pZٍYVNuܰթpRx)xL?'ۗJxcVWo]/qϫŤ[RSsq/<']e[ʒb1I Gp.*o# q8 L^#'Ƥk^[~-eغVӝ G fo.q \mrʲT)h/ƟKYa|h~{o40>,n{-UKt,gt7zٵ[T?[0J|(N6cg52p } dWJrȣe 8zPeü?ifY2h_hjh-l4jźm4K+-W]Gx5ֵ4tR"aeeOj>:%R5֨Vt*wxl>S*2?>p`xxL^"gҍ(jP”}SSTʬ+N5ի^<C€ ( (?( ( (??LK Okx;/zd>8ѺkI/5eԬ4ExtͅS sV53lWT+`TX$jFjF7Mի X,!ЭC ę.$LL+0Ua, ѕ*5^#  ϩaP x{'h7ߊ >U])OMA|:%^џLOΩZ\7V]gG=%9yʧ4'/kV~'BRprWQ:1)ƪgRjFU"F4%JF5Zr %֍O\d\K[iJZxY#'kZzpe %x:2<#_|I\Lf Pd>|oWF3xՎ:u0txs-'8+4RO-alg(ucpR3u\3,M,=)>0|G řeYGT>N1tpc ^G7=DEºγ~񾓤xKo9?ju=R^ӠG-B+Y.-Ig7mWIˈxciiwQX&aN 5ք֣^*Ӛ% *OJu!uu J9Ik>m<%~.u$M e@I%ƹF!)Ï<}))(֖ )٨NS|2vtMBޜ{8_DH\b(kG{E/7ğ'XWу)tߍa7o_ a۽>-F[w=[Yy1? F1URo7p4gcU%#€?$?cH/~χӋSJQwWaU>9~>&FGux+r%X.onP 6q\5'\cOE?WV ]L?3JR2jRѯT!STiT cqtf鼺a9VJ.T*b R*JQm,/y[I)5া7BmLx'SpZt{Fm h]D fĪ63%qժ|?T29w96u'~zѭ*TqNt`G$N\Wf_e}lv)-Oôʛe%/l_o|U~ғQ/i/1=ƕgpOuyXW;52]"`k鳸c|N,UP~eg(x.GfxJI}> 20߳ѥi7)rNRmPWza@PwN eS/5?:?\I|ſ}g%?Y C~ EC1~˚}iiW] k>Ԗ tŎlKEx.ZtL#@75/Ù%WXzTU!0ЫIsʒ<,)U%x%l^MY%˹a:X:YalXNe<TZWo_aеiּ 7Ɵ&ӵ|oiƕ6zޟ Ϭ_MkFSÙi0a]xxp*:}gGK/`NG3 b18;NZ^YOVudԧ#_^ggOBx]im_U>#oxkW q on cp2-gK?f-nf6kY[>x:WC3<eyV.8կe\+楉Tb)b+aq,V79V]]c^!4ySV`9n]N(V̱xjZٵ\VsT12eh`q\&OؗB~)|AI5Ma"-뛛4˫- Z)?yiQkZv^ԵKS%/[Yq_2o-aq/i*xlnzܭFjRZZ qgCN ogi*䄡e__xKOs (_RuV+/섯O?YfU}o}_W} @~-./~Htsig-WڿM&Kui^!8,W(U.0u:g[^=/mK*.?m  Ŭ5Ll,f2*\5\E_eWV05NUHЯ(SŸؿDŽ%9o?]CH>$º߉5QCkm'K(>͢xSHXe'71p8.y~ 1j/ ,1fxU3)ԫV:o3Z`~Y'"q3# xCp7Â1ٌsl6ɱMUBPFRBnr<>:8 _ U<.'bgڂ (?k5oKWA>9W7xoM_>|UɄ?}sg/1h33*?S>>2~͗_8|Za|H__ }G.>aj]F<=ΏwgNЮIckk/~c8ƎZۙNYcr}_J[Now<&QFT1+ :*,5J>ҵc:67w?b3g8,v: ZUSJ*c:.zj|H+W_:h/Oƛ߇C]Ck7"-CMe0)$=FOļ%eh0.wv31tiJjpU(Ϟx/*X3Pu%CqUʱ)غה]JShRa S95?S<[? M⾭iu] qy&Vj[[C%ȍ|G3 NU*t(c)ah'WPnPs+ԣZ>.ͩj9u/\ib+†ahUu[U40U+Ζ B**3s?ni׿>oY3>'/N (k\W>$z-{8"+8Ê9j*8,"UxR0ei\Nv8%ZT<3)a0\3|WajXL3,M>l~eAcs >/i*xj|xiU& pqX&ՙmwXฉfxYu-G,g)$h~**աVS/է q 3V'}9~)wŸ|Xes׵m?DVne8S7ЮJ׋9 )18•ZIT*Ѣ)y7 RRTle?m55(Q<p|+ ڲ*ΆUTc'Js%WN89N>>x\7m|T[$cPyu_Þ&[S-7ԮtgU{Y[H„O E |cFx5`hIԭ帞)Xxj؉MT2,- ?*Zc@ CAGо#zu|,3x3 [YxILzΣo.mcDpKu:]3 L>/5 V x:kX9S4}8us)`4p4~5# x᷊PXVE}PE'៲s6eX{/9[:8o:eLq_,n6YS,S2ױsZQFl7O?>(}rscq\RNrl=7SIΆ)`b0uhbk״~P@|g &Ug_7pY)gN_aj^˿f$fLɮs+>7Ÿ /\WyA㯇.h֛k{j>Ҽ++|MGUmZGxg,>GT(̰ Vh޾pTxb5<,X> Z q)/`ykP3.<.xkӍl+&UjR rO8XN*:cXiJSJ2Syso_%>mkoYǪZKz&T_:_钵5M 8L6?Ns R5eS_TSB,~aTdy ehFa35Y/̣}k-\>U8JX-MvuJO M/~W1|K^9dž5-Wׅo/|z4;Jeh49uHZ+WST)dGRGf Z."5+rVx?fBMJZjU+F rNSүpuˊju*]–+ [ *aeFy}jG/٠Mh?Ru WI^}c2I|/<[YO;᷋~+@Ե ;v}6̞.gIlI?*L?%[1M/~zqr!9F)3^ &<^?Q05\V"J1NU%4fN Τ')$|q;.|-B|=ӵSF>$I\xkN{Ṯ<5~ \$o4Ce7-Guf7}|V0؜ QQז4hb+7Z4Ua+^ Pp#8Z\&k_-gP1jT%r0ҍZӯJTjow )$gO◇4kwW?$5T4zu߅ҵ[ۛB{=Qg&V~g8c:8nSQp%\EG|“q1TN:WW|ٞmx<|z<-s _cE?JXj:qp+3ПP@Cɿi/&Y$'-VJyWdw1`/2٫??%kύH,5d}}P~xf_.#v'oO[Kco>F,MC\윃-T3|]ɸ{1Щr *Y:oJ]֍*VNU^BqS=1^thsJ)֜j//4ߊnQG]c?|mKw>'񆰗:̊^6閳5Cr+xc#I΢YZ/~fSQΫNjT(O g[؎!Ƹ4#L5*5frS8S25%J:u'R4 =~5xΜ4񅅍xK~q/ F`m=.{=k+AIWML 0ˇb!r⿰8;X ?rwZjω8j}fMbs A[[ժN}K G3\`B_/ٰM//>,|:x\tWNm7U}3Ņ+O)t^u'M5&kb2=pq |K.S]FQ_s照 lpq3굲_C ~_-/xVjc;eXiž_8`q8EhCy)^ L>&(c1FaWڟP@~7|~AjcRK_}f7|s =F5ϳ|GԪcZ'WJpg*T&%6wOxk?:~..49g8 jJ5gXnxQG,q Qb]ǟF Lj#(kvfq{_|Mo5=SJEg~QiWÉaZկuV?0{>WʕjQWZsk)Jj\u#a(Ζ7Icͪ]✡Qשp8K ,50ԩ.Yeq*4R:x\V/}bu/?_KY?~_ZlfjUqeA:rN|&ppTibcG2t0V^ُ@~j4h|)/7>8u7O:~&[Y}GPEńM\$2nqeeYsXWq*ө xň|GTTUgR* 7fX? 0y]lUŚ9Ӝ'/cR8%x }iЯHsW ?/m^~'M O"5斺]X/5+'$ԍwd e"1*X*J0/OC,J:t*$Brͺq6kP2\<}^\f+UJ|{(1|%t*j9uibR uP@U0_'?;Io$WؓIkh}#XHrxw$3꾁d~@j`)IgSƳ|='Na.SW 3Prb%,SB 3fgXGƜ]LzQ~<\ϳ,_ ^|+b1iRU[Rq2U/E sJo5~?ſ/ּ)+xo0̓5ʱ28㽼 ʕ*F v'.ҥ1Pb?U2~͟?oȾ kjto_Xh:MG:ꚤ}:V0;;Luk[ɑ{k{,v*q8,«xj3jB+WZR UZ4+Я:uÚp9U噤\~ ,}*2XV:5ps 5S[ N&| ~ kɯ~>~ԦЦw~!|2&?fOP}C>k\XZZ|=\/~zzq^]mj+k[p׊|&M0<ϻ,*qX UU\JT j>z>x%_Uӫ:ʚcgK媏qe:WRST(Җ%*U[){J^UWRi4}ۿ |/S.ec⮙cY$ӵ'՗dӒMƗc?Cy-Oy%\YDm C]U(ʕIUTZHS#IKӕFQʤԍG)TSF4M)*WRRUc*QjPNIjcɯm_M?UgLW[b:r[Ak8? ̵ҭ+tRW^}j:| N i<)ju/4ſfʟ_"qUeWOi,G9-Q^Xr:oWĿ~;|wJQ|E߄<7]Kº' \uok>SOt2 )l͊[1/omša\&_O(V[)EZT2Q&CN>¤hpY1*8t:ʴ!Gr9Ӝ \)ՌV5ҵg)҅^7ƟL,o_'\u}k ֓^Ka<G k4y,6rǀSxg^u^tX}:NkRRTe8ayCpnL4!Nڴ]Q8PZR8:9J$+vyXؚNr/ٻv'~Ծ6to|o7ΐڞ|hK=2[++[ at.Ynٖ)} =hK0+&/aGK%Q*`TiI\2u$ž2S;.d1-r#m9\@P@v]?ZOuMy}lNLmW>"'ϱa{茰DA.9kM.#J?i*rJ9Ɵ,cCRE9' ԍ5FuV5#9I(iIr{Z.[Yɟ&˟?/Z C־]/)ouiL`XBnh>Z!f>ątm+^-kLäz/W4h>!'R]CS_˟e9u,=GOC*cURt1U}Uz^ÖMilr}vTuO:^ﵧ7S}?˯2>|AMg7NJ 圱XT?-loO $QRMZة"wUe:NHӌjJUZnXƜ%̽Ztk)ԼiJӧR5!*t 3u]:JN,5VxZUU^fO)@1l{N>+HxV=3j|FM4ؼ-WLM˺[_Sвļee/zR:WJPe}mq|2Q}),?"\U<>jUqwZRY9M|*5KD{3[kƏo,6^#YI-7Q_"ͳuӵ4V+_]`&8"u5.:0ԾRW:ӧB4\0z?d-0PxhaN^IkZ&ToE{0Z͞;jO:äM_i^/SsKf-hӣ-޿\kOuokޝH+,:q }؜u~/jbieiNjSJ#թJ4a(sSZӧ_Ek`uj)(*ҔxI(SU]joKh~? ?|5iZ)[m;Iҭ" YkX"KwH^"\UzZr6GN )? )F!*$УOFIS9)ԜJ$՛TNR#n5 (bR pr7pJgFsYՍIRU*8Ӫ:-BUE ZNQ-8SNQNͫꓳkK{;Xu/m9|I_\>$l?Xh:4M;z֦A j]i+?*+V9O#̩|gifx|%L *,Z""& ՕTeN?q|OS+JS,,)S2j5W:ٝC:4o B^qԫk_~ > |?Ӿ/j>Լk_Ŗ>%|4l>4iAzs٦˩[&07T.,]Ը= j۾63fC{`|vc{AwsKE1[.w `I~ź4)Bx[c*•cqgsRZ\kftDi晫pUq0 S8¤`00 2JThN?a?/f|GĿ?{J\Ɖ[jkΖ^j~u/؄Y._E,o^ږ ңRZU/K0 NUMB**R^u3NJ1CYk0qƾq#K_1MS|=:#J1zٕ__M~_~\|xH=(m>jZ]jPx^ aIAִm[GTp8 *P0x/ZymLЫV֯RY&|L8骰JSU2~ci?9xwV97{ h`RZ+㯂?hoҭ~"3~N4(}L:'p5p5ogY'-dl^8_' ÈuNuV<¼.7 V0[,{RBx #/~Пo;5ό!O|LN_ƣjgQV4+sTZ[Cw\tmd-܃'40|3/+Օ_CcUʍ\f JԣJpZXxN3q]gY G7Ϣkbn' V7^xi,3\< SUХGNrQԴ%KHt9=L~{ 4n$-޶_P0 C}q_闱麔WPփPX$KKl{evw76c0߽pCS .* bjP<>"T5aBG{XpJrRgRgH)'8*s.Vi~[%_s>"|'X um.ZfYty% h c:mڎ;G (go0YԧFi :t>gMs*t3!dNjFbʣ(ή LMH3V.זN7W*wX&|S(|=Hws>oK+:D> "kyݝjom\.x)8%|}n U+ԮX_kӧB=\:BI:{R좖cs y!WU?J*4N15(΢+N%(bXǿ!L2x\Q/_G-oh~"ϱ;풏kjwڅ~'v ,xZon+v?j}!?v27 q{*T]Z> . tiQ*ɼ/?kԫ'ʭsOKV߄ W @UWĚf4Zf}Y ;!nfK=ŅͬR?䘬2-*K jVx2XWOT*+k˲ΎS f4fue2xH`GSΝ *p8ў*~ɟgO™WoB}v:ʼn>6-qC>ܸkh,bY|9f#(ΫSͰU9D#y`G/x:5Ж N+RU֝oo*iPN'CS&F,^'V5csRUaE󦤩ƌiqf_ڃc>xu-C.31U}ب'%*bX|O۩|<Ǎ6|UZM xkž ^L]r1\juH5FD{/r>:*8K03 KJ?ü& GOae:Xl=)1C /&^$1,y|r+aeJ<]BU+$15՜!CVWi!@Pɿύ~ |_Ι{SWseGƺ `4k4k5՗徱ູF%4X:b^Z}Tq%׽Ju*ScJwy[Rsx|:ѭaqnyRq5!T:jad8ކ!5 N47~71|@3}n]WRǺ6!$Lw.s2,b]ټ o)0GaO,0uh,'hZpRP焅5FJZQa2/1XMlGNoU[xNUp>Z)V[;$>Ie' Wl|Fl5j۶Í Poia/#̗ <7&bN]|iuc_Vc_ޭBRuNώ\o#.\3K2tR|VY(tVˉk*tuߎ?ip?}??hu{ÃŞ 񯁵xCIΖڥZhz]My4"A5e ΦshQbrfX*" b!Kם›S5iG)AJ72ks)s8MAөr*8IS('8ӛMJ1? ~:^׆/f;@\_.xĚظTV-iZ[x8L1XyLrөB5:TaӫҝV Ԅ2̸?ͳ>89av<6UxV UzU:>Z^”牾߃?|ixSX? rPR#ueN#f"fk~!cdղOˣ[V)a_tgu՗`ٌ2N3/Ify~3 –+l̺"b^"3Zy eq+x-}Dit^W7~Ekhvp/]O ھ [cr6aax*haxu"rKWGNr(өTN0xy:ꃜ. *|!V+buCx|-\6aJ8|N] ^QUWl/qx?IGXhxS[R|s`44C-zn[7FdԯQ.-x,/gt1L7Җ1N?5`CUM狍 &'RzZc7W ŞŞc.iޤFan`M7Ju:]گ5Vկ{qY>W_$Wia~:BjRn2xqJtjGS/Gwp8W/aI֭j;3qSJTq4qg*e(έFPxG9lQ.'> 5$ۭ<9//y3Dfvck'5*u<7q+V.6+_*uj8,V+Z4PZq0FU% wUƞ7>+|o}Fiv֚ xsžŔ6x~{;ޣNckaߖ`heX*Jjd1*]ͳT81K-A:f\>s7leϳlcFUG,u0VQ15%^'1cq'/p (ڗmFh,H DuKKvqlj@xZTr <ݬhbQûWY7<' i,UiE4)żW=nL ѝ:t/C V5(ӛAg ,:౹V'+ y'\G[F'-*_TR%\VFX<=ot;h7¯noso[Jfd-񕏍u/lV.4Cyu: `*x1 p Vp0*B᥄T^I֥'WN͸[#46XS&USW>8xW󝗱HRQr{ٟ k[>"Go 7hjդѴѯ5/@Og[6vY^#j2OR%:Jyt2JyYf8lGf9|"xS>` ZtJXe|cN~ޚ1>` ̺K*?d5/8?鮼RnܶhY\j#Ռ-fnXK9Y>&37CNU+8ЃUiiT2[zi6-t"E^[EUogq Ok(éj{ZAK[YLPLƿֳ,z0TYL>w))qT*X`0u\*ң pwr˰_eU2<m\&c(1Ѣ¶gW~gK J1^3Z~쏪j_ڻo|ώWowO[5X|!k;6M8xº7Z M۫It>pʱYvi-l%: ΥV,fP0X9կ ļ=,VUA 6r^"h`s|&C302O _ *jjԫ0C 8V 8Ja߰O'~_<O |*KGwJM5Ƨg1OXC la-m-m-5-S8gx3,3rʷOBe^j*lZὔ!/aZ_$I+%Kd- (cƚwu kzo|OeY4:ulKRrj"kChڵbmr)08x : y[G_7Zg%:uƧ[PqS7O~i_}MTVe;ӷ]eU6EiW}G>Nyˇ8wU0yת?T֪._[1}eJ=8{Y|"~.|gj~_H]L GKȝ:l==L6x]q8ѧp,VKrMV԰)ӌJ2ZJU)N_32:=ȸi}W&ʪ`Jם R)%FsJ*UUiס ~t+|1>1Y)o%C`q>ׂdQo"t떊UgUCugYF㾯J0(C R,<rN˿s5%۝q8 OR+ѫs->(־ xXSVmlE5^HSMCP/nn_XL-e}9ajURjJD(S^n0JQҥB E8uwaxN63ڬ+پ&.tZtRq M{֯TT^q(RO (>+fߍf/K=[|?k&ouK ,pk[Ɔ(5;|ucsbp֜rʸ*_V^Bl[sӧB0cR9?fqPs9> br*q ڔqtiarL0J)rUaTkՃgO_x~(*o<&kJoXXJnaD7^|Os0 ?ciP˰~h  RZ+,XNOeIϞԝjRu|~\ۅL<1G̍.hbHrǷg0V_}O!~Ŀ5iUMuA.-#^6[+ܭSilj?iߓ2JY *У(cT*i"sN2I;ףJ3),S3ɳwX!EOKGߌ*N!GVڴiok?|!l5{x;K5 SK{?PԠFQwO/>ۋcs5Mezyz5+ί[~ß~1~О kk'/? |= >jvz}OS׵SK}Z~]O$^S,s_3 1jRGSeFt۝J1XMYB V*.xূ3 x5ʱ]`kZ(bpZV֩_0bXՕa)c0QRtQ*+ƽp (x]:?bn$Οy7ދ ɮxq5?iY$Iz<c)bӄpXx:e:0[%.j^Prn-TSy~^b*aVN.VҡS/T*w^**Qj-ds_?~0SN?<{E_~>šk%Gc ~͍6/ ڼL$rsTq2uU\U9beJ\1%NT~8QrԣQœ\\I>0?eô~ a+IZG(W?i*'?&/^־#{)t˽KUO ǬƑ݄j^O*iVއ4l r51lM$ڹiatW T7?%USe^/ ezdapTX\%\m,Quj:G ix_/Ms~G|D𥯆'/|Y$Ikmu ωcE[FobK &8(S{?_/i6h' g?ō/C6mGLѼoYB MSTkY5IMsw;TWT25}c5e.IF\xX~ =7Pr^,p9s< j9}\a\p ~c,.B:8:ekYۖ?L43.i1.SJꘗa4a:0*УT/:0g_o崲|9[foڵقs:VF8L*bqz13P'L~~_ mx {ZKFxzKwƣ<6ʶ}ۗOOqjSj:P~ xʭje_SXm{SJ-B J\=]epxJ1x]h3 }hTօ8ҧ t,6S' s^SVY@P?_OkKK/~izo+oy㻿wVK:6qCqa9^SR/8PU,|c uӋ!S;2_W4}:%;ГޙsIFM6ELFqTrb-֣ էZ*L=E:K J[3jq%˰K%Tc:JQuSB^ߋWd|h|GşjSmuvzH6r&մshtg?h%Y#1[|AY¤y!s V# /އ2U*< WOa済}_+,ٷE*x`-Kײqy|fӞ;Җoe?^OWv/kwĿ j~)]cLH46h$-I&Qi9ms噆QWWuƝJpy.jcf"[S%9UzUjTಪmf3}Sx2SbXLoK?)0m# [ QO{*mB*h迳_? c¨$ /wᗇcoo^(5ua3I}n2t3cRb 4/J18m j8ʓ:3"C:?xcr2\ZiU#B/Z{X@iA~:~c|B$ +Rui/%V]ꡛIVfFU#CUel]iU(lkJVQ9P/+,6 uiex1G:֡KWTiq,.UjPԜ9_9[~ſ> x'Xᇃgo '|@~ Sֿ~&cAhz.^t `]DԒ6ht+4W`a eO Y]Trm|MLj *t):Xl n <7 >{+sY7V:?, Lb1T1*1 08 uρKs>HG7-u:2xdܻ8F)VXwIaFԧ*|4JXZ˪atЧxU*%?dsΥi{|2\>6 qs^8^8׭S hE~_w>~~'n!Ms|&N+oY2Ne{;-,ӓK'#yw)<< &cag ~sOb㈩SBX4e׏֪b(K;--|xlJ1r >*Uakaq\66U!<"0hQa_k_3(1hK5}g֡)|A]Cw:pr|aMOb0x{,& &7? N)Z*UWV4Fj~c.,V\$QUڰ ܩGQBU լ |j?h(~ 'O?*[x>ÿ O ^dt;σΣÃOGQ+ؠx,ଲ|PQb($hK0.rh&?rS >.:,>7錨|?!Js\f:,UL@:uPx,˫_Y\6Y5B?Z"&a@P@Ks|U+#TMw ?g,SY>x}IxH&KE"vV tP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( (??TįzO77W5:T*~~)[G |s5h \Pf]*>)E-lt}* wjz:~gkaikP%}^y,yhJu)d_,[8%ZMFPPVьUIIBP2O-̣\CuT)Ʋ*Μ ԔcP@P/IϏIWo#/c fa<~N9<'Lq(6F*m%wm@?7/{u.~i/ G}O|Vlj>?i>eo:sAuZmү/-TIWd9/&1ԣlm<4*X]5:tGW(o _׳ ó˰iƜ;$xZ|Jot+wy>&wk#%\' F\6aFXJ:tktVFFu=Va΍jm KWE:r)θn3ʲt_b1 8^9~cO<,14r*0Uta?Wj>0;L.6< }֧^!>'jז=tL_Ef_X ֯_N8\5 -TեZ8 4Jf WØ'3ʦ?aia4+dzuGKV=6Fgx?~QW߀#5/ W GL_V%HjZu4}VeG&RgS a񰩈xEZj9bpNjħWK 8 qX^8쯃rR\;G1gYANxOa8ym8JƼ5 F9t}`x"x<;⿅~j|U1gtGCG5S>M %U%r|`cpSצrm:WAN~u^J3NQU#p_86e58mq C(RWaR*J' }b1] 5U"~H (??'7Z'}/n.Ꮑ,|Q;plMFNҴmM3Bڞ-5Pe5t*eZ~*1S<)iB_Z ]QOu Μ} EJZJia'T ,*„g/z|EIB1WΡաJRU8J8_v#g_[{ɾMg>,glFAӼcgR|OPI4V^I{hvNqSh}j¤'<'[%(iSBjڿ߀?~9ZM[Ꚍ2iv_kZ׀%ɨ]c -B;Qi4駍[Z88x)\-z*Ԕչs(WUQZ9S W[:SqTTpq?Sy8JQ\ʜ!R+ Ftws|N\Aia0Gk'!?9MKWD3K mumk֣ye^ARszXQ_|%nUPlܹ(SUF!ZPСOG N9ӍGR(Fqz`8~ںÕƽvS᷌um;FҾ#k:7R:X^89Wuf'Oƛ Ԇz,5Lm 5hBkҨTNPN>RҽNwJ:sWѯDrG4q,RrF$ԕtu!e A(JPe N2(J2RMYcRNqNq8IJq%(4$iԔP@\[ww<6qssq"Cooo&y+PI#*"+3iХRjF'VZPN8Τ+F0SݒWvpU*TaN"9mF0b)I)6۲N>mS/-|`QmGTo~#i:<5Do\;𯉼AcBmcc5SiºbU} eW JxnpŬ59է MZM3>'zSuM zu._W(Γb4(.kr T!Nx:pQ>W9 ӡYPUaϥhFzITPkB: R=bGr:Eƽ5Tf+_,Ux>4}"|6ΛO 5K{IV;km^R W6V*Ux´a:n7'pTgKuaG*NRNa:xLE)ӄ*N҅Z5tjzN2.og:5RWʵ?|4NXn~q [[(ӫcnQ9¬e:Մ*Q.QiÙΚF)e7R* IR*6N 2# Z-P_<>JX|N_2 (~4~G|Ji$-'D|G}cKaNhzm>y ]'ybiURxj^ڴ!ʜ)JsVPJեMr6aJ4&%,Mya՟3JtB4:*/(N勹/A_›^T~?~ОkfmcYτ%m;g4>XYh w}2suki'UVFq} OoYMFҍZ|j4b^S4CR q8PMZNM۞E Sש1%uf] _FC| uo xGǚ_F~$OsΞ3:Q&)ҭaJuכJ{\>xNtxWgצ h0/u{{huHPR^]YZm Qc%B?7JUhaT9RV Dw cO×R RLf JFTgqzJ0RLVMUEҥ:*J2+` (/[ִ 躿4A/cR%m/KPe +b#VsVJ๧7bv4F"*a*T*TTR\{Rj)unQ'i5ZR<[i:" BK5OYFxzM3yں^[ p3W T8kU)b#Q_䪰uT:n|AՕ.lejx<$1MSWQ+IԪiQ MթuUQnΠ '9$)F%9JRiF1JRn$nj`>ӿm ߈y㿃>~- _|3ktpϩYxX9 mXum:S}j0W'M^98htNIU\<F֦b`HKBJ&SG ]G،MXF+Q! S)g*VڝtxCĚouJ[-Rh%+ մ);z'I*8lM*8Lm0&|=x'Wn -W"[xcP+Yl>>}+O1upӯS .jsRZ|IWS=gR)Щ^N\X|gԫS*R8ՠ'&}UzU]7^7z _PԖP@|?gGG }l^߇xCH[,,l_2_U-'E6>DE3.$rb[F Fu*¥JTj҅Zx\2OpBV8ԕiBLLPoS֩aK SJXx\-:؉эL&&3:JZN9ԏg5ti_ סhZ&%Zj6q%<6k&kfk4wEˎt F2c,n[f<,\stTb䒽x[WΰT1|-|VcO8 ~#*FJ_:qQSrUjJGП9|{|>4ƿ,kSx{?|EN[_xV|9{^YCU5D(pNnF'6, a0 ci`:4,Zձ8N"6BRKxj5a·q]Øl�Iqr̫TФ`VE(K^P:a#x 'g+kBek7y_Ι7EP[;k]jݎ=;19r ԫ`jԡWFSf.N .p8J4p)ԟZ8Nǎi \#fUԯcjRV?j:(v\B, }׬}lo蟵OGaOŧiNTptjx p¦YpGN9f_CbickKN1}\= gNhƮ6J45TP@s+W| w>-խt xgKֵjzV \^]4i##+*1TRp(K >NUj_OZ]RZt+jEJFz:8\>#9(Ž F'ZiѡJYIddy_ZeW:j3Fu* _ t`+J3u[JutgڮZZ>j{2[no-6֖< Q 63v2pL Myƕ u*j*Rj0|+Z)ɤ]:sRiԜat)*)E-KS?|iM_7ُ8%_:vDEa-{TÍWƺ}Gz}!Ygpyt3fORrr긊8ICXE)}buhYQi'#9i~uCxL++PUhXmz9*UiVkb*JXӥ ?~ ?i>kK6["J|%iz/->qmi6rޛ=wa<7/}s bf[ѣNUam<;NU[(%TZ~ q6W%ZrUMC0hU Մ8ԃRJjs8¬ ?A^>1+m{AmD>M/o 7,uLsg J XĭϪ6r!"hQż DOS*V.TgT&:4ˋjb|;`ukОg1"$8W*ЭU2=JXe ũRh~o&o4*Ⱈ+975[V~Ocps:2NJBup*QbR&>( gOOh6NšL:ÿxXEݜ]Ziyoul$})|{ŞHN*cXZ8jz)CxuM{ 7/ 'Z^9x<3 }^/xYTEޯkM6rAԚX}EH|_.s~) QlRQ1.X4h9IhbnNܫwtwGϤ̢뵙 U~9PE^_ KY&V77BKjtWXAuqvzu_GdUSe/0J\ԕ:!BUeV8gB+N' {.*5G3Z2LRi8}n x֥^tq  ۼ3|?/55Y?>kĚإx-|#j]Ėh?y9fp>cJL|67 Rt*{%UN#ZTheq( |y1x0kZݽ\6~>YxRI[DφdK{MVuo#ySYM.G 4Z6u0XXUR]9Uu1YedJ poU*S~4#8(8m\ږ.3ˣK GS\RWMn2">5:.?Vz6iε3i̅cn.&r8gn6 *8l-)֯UKݡʥIu*MƝ8JrQS))k)T7tRr!6ϊ?loÇ_㟏~ kmCׇMHv:> ;)2E^n#6pgBb3 X~NxׯQ:VF1)EKU_4?ٮs6)L E/wR¼L2O|pq᎑w޶u/ײvXjZ=ޕ$k:F>ѧjECylpwc5ugyqh`cKBY< *Y)9j#&RkSNp|>"|."M apy<^Ux (g(eӊĪpG ]῅O>0g} ᇀ 4όWJ}m WIX|ON2rRpWx RÝ啩TK -:n21z>Ҵ:Xll[⿩9v[dYya2ujLnW(GSY`5e*+S_ ?He -ǂ|a?4_ <4Xo<1m.|aU|1 KfokzOҥeL"*3xʘ  cQ{:har>"sxV"t骸Ja#QCJP/S8p<8WCf,*SL^*8UO8+T%SNR0ڥ*Џ[_~6#;.~SxW^hf|7 LvOceqy~eKr[ᰯMK;+RR>Ztld)b0}iPt|Sr>eX0ܯQ7^k|8j8TV"%5%V5~ů@ (/ /?%֟}ko'`!3 98%leNT8J؊OkѧGV G-W^?K| |I<{mnĞfi[2mCMI 9dCweysY[[]< 5iN[RRiUZkPB)N|>"HW(tq*SFs8Hܧ5̻ ex^^1M)JJUaN jtqjWRzpNp:B (.A~|5|>0~M&\>-<^ lOT)4CQht?]Aj2YjAd1S*e&PRiPRZLEZѝ::4ҕu[C䳾1lΖGKy\:ż"}{J+R^ޕJsEJx,nu?K`aS4oZiֺ?՚Xj:Əi+w$0\\i:dV rjZz]{yf? 'UJ14 Ik|cJnhέ 8{UR2y8[0x)bp(NfJScRSZXR#SA5*uvp|o@ >e}O/>&Ni +t-Q-SEҴI܋_ͨ%i).?[x|fgB*XP0i.ؚѣJ7KN,ʸa(c'fr8J*)ҧO1Jif:<.*8um߄/cF>7M?t+_;;)m`Դj֙Y[{j_Ũ,s}o}/vO`s5zJQ`kFTq'Du姉RUΆ\V#F|GeuF3s"[aЩTkl%\=|V%B,ESr00$o~ xoEN% O{ ?IHƟ }3-|=?|-h^-ӯ!ӯ DӵMkM.!H, .m.n;rla*pa*XjfҕգVoe:_V֥BYdi3as<)JyfmBթB:Z+pUVjѝ|<#ص`P@y?~>'T-]]JVY=_2mgk -^o2L,qXjֆ JZUHNpF:UjR(СJ'VZ0n  {:N-NsV*hӄb1iaWN /_WO/#.࿈>fk{׉axzؼ]z8\. |N"(У8SV)ԩ)I۞QR?Rٛg_:#1[Um:6shZ$׵K6]a^4+&DfUr Qb1o:jVVI<4hԤT Nt.."%c R居lʜjBuO^51ӭ GB(࿀|K7NoxN_:scI&9 BN[ۈ-Et晦'KMN*p\WUҡBu&|RLF"5xVcpX1XMV:)zr96NP|MyaUUJwVς~}{yڦ?xx[YӬXnuXD񖯬kWoiֳs43Fyu V Pq TSZ5UΥ֠,<10γAc=C?dѯfд.5INsXy |7>ʝ:c?iS1cp[5UnVa uk:T qXܯ:qsG0GUpn"6+{ K eA/.sO.Z/c 7kԿ?{|'oO> [A7CqyC Sj6 W (׉שn*QqeQO z|5~ k?^ds8nycPcik5捪}jwzVywqY{٦_K,l.29]`(fyf:jaRN|&; b}JY0j`XGj9Ydl8˫9Jx<}8|K:tj5,6/ ZpjWCV~, (8N|bO@N3U>Le}/|#˫Vjp\ $kN1S5i15W9IsFQ̚拴կKt3`o]ծo~|[-{~$Do]oU-cX-?ui /lFҍ9cr L<?Rܛ*0J^ΕLml& TF H?;ưܝe>!*FwnTh@/#7xECZ{ƲmS⚜j=xOS?`W3.~ ,.uԠjIaO: itr!o B9_RO&"Q+? ??Ӫ:Fo\#H NUjpt[Seo uE/g^tce^>:qJ[c.0iJ/"YD7(㸖թ.fa|6qPJ3*rrFH? (m+\ )Mmo)4oyF{hZԶ2w#x[vf.UV\;q~g(9a}q;8Ab0IT qbڇFc*iIשZr):0]NJTac$~|ƕ_G<=Gi xS&Uà{JuV]?މMg8 *_ZԮV^jʌ"ɾV֊LLVST+jpukiB75\[gk+K]qko;$eJST֥USR9E>}V#M%:jV'$gdҺ{?SȾj7!N7g4P, I,MF.ZAza ^mȓ\V穀,;{IW/_V\W' 5Rx67:s$'.b^ܴ}GڭhC5m_.&E!sk}]kI ][[,6s!2w(uHכ<5'TܡR$eٱ΍pajJlSX v\MziɒxD$,.:~,JWS(X$}4NqmJ"v+ FtN( 3慜Xi27金KI5 B5Ek˹i..yYھ7m^H[%`,|)7)<;NOV3u8&jqXB1^QRm3_ wƧiQem4˛H.ŬCq~ېqnrdܯ(r(Rӟڝ:v_Mɹ6,ezZ&+q>"r\F&RwFG:['VoMjqQ]鹗zS]a5{zΟR q4_F.YFVR咗,w~?>9eo3xᶇk> o|!sM =vZizO^:{ﭢ`>̺EUeFtZ0UBJsERN|~…l+ft% u&clEF՟jXyPМ}lE'_^4dc,_~?|;eyB34rÍE^6M>jqj=<^Iif8\F1J-J9rs58JLR7:Y|n&)GR,M*ьQs ^Jprh'1),EZrRUs:t 5wu18eW"h>bԕ= Muk)A!𗅢EPJV-|Y۽kОEo'oJ./git YV\A+5_kOK^g{{៌,Ɲ×K?Cы$<=k3?,s]׺yA"=lG/L|#+g?&,L=Rduy~;~Z7ti6tPkzzٕk&>se*).LYe&K"ҽ*C&1UyVSù>Q)|7'<+Uh,ˇQUfQڅzѴ!URlobvO6ReA{;:i1l5Fe0]M]yig5< _G,3Tn67l•%lE;s*[GR_~{|F|Ko %/M5Ƌb56I4jL~vHg}?gLh/z?#g)2v"4q82* h7GZ8)U_R童 QUm8ghͤxiMn-Jk#S R6y<7qPIMR.¬e(7TC:ܭ>^{z˛cZ/+3MfR4jWF? xF6ij}.|T0z7XUS'*VY==걠Kֶ5P@#V(Nlֲ~9W7xoM˜ܳ_>|UɄ?}sg/1h33*?S>Af_Y|k7K= ڦ>aU|1h^ c4/- [[7T_ ,ŕ&  Rbj5fUFTh|UQ>o8k)l6],8Srp%J*CK*Z o9T3Uk(w:~on|%?7_⯉v]%s\MީopW/5y||<peѧZQq?[)Hぬ첝LƯ]+* SFg=[Rofiee6–37kKY z԰7X4ψ-<0[|J{h:U,ω5iٙeH#<&Y*s3e:ha-NUqaNgRFGS5RT*X͜L+fJ(XlH2NSe%',niJ?gJJ#:h(9xC/*쥡.ς:s/~&G/XQѬ M:l64sKpq_yar YIbs M\ㇱ9oR׳®'1ũWO4kե9~/ʱ~3j{ϳl'7F8VqN_l$hYU:X<4e ]iӏ_V~P@e_o {ģ$_1[8o?&O9zg?cFd&xD*&&Y3য!~ΖoO75ۏJ|)x-[TԛO4)}ŵtDKC(p 0%O"ʪRf.^V3NrU8hR(:XZY<%LO_7oJ<%,U*2f*Qc2iuoU_&B=#KA{ibe?r ԖL4 k^$ׇmb/l֯Fdփ_Mott1 "`gʤV'ڸIRy^  K hFTWZ'*UJi*0W(0Nyc0,:4# W1eV֫*tjS JRֶgHvMkd߳_t6m-EħV=i2ypk^+jDIm[9U9ev/pn䡙qNJ*<1zxSk`q1xihqw8V48( t3̣FRurT'ҍlaN]Z?\|e{* ~ 774 =4-_>wmhvׅ[ڋ Xx'M`_7r|¥o0u /ѯOZpheb'U,.^g,-;2>7,SɰyW9sl&[OB5\vOᩬK0*usǟKyd=VN49eMjmRlR6s2Nqcp8Mq^OS2 %(ŸҤ8{^j0a;eΤh,(򇈔H῵^[SUa(ʢ8JJq0w7k/T&|%jSW jdi ^ZcE?*T*LMyz0N71" V7RL4r D}7TT[(ƍ:_Ϝ=6/)lai`pRb1l5'byqS#3Fazʊp'b*~ 5mG c⿍"<[>$]êfx;RC#Ӥ}:%͡dy!iҕ:ng:5 *1c*8zҥ :R?pX >b0Ukęc)e˰UHahO BiSӕZV0NWӣ E_इ2 ;8<ھ'C'K?OKa#_N~P@4X$ŵۨ|?Jbm߇d;Gqw.cIa2_&[Y̬ Ƚs_]Gg_GMG:Fo^8kֵ(Z;/W}*ѕɩZ5=_Ӭ+R\]T8?sK'.Ŭ:2ӎ%ia`P~֌X>i}v,VOEMF# u8_:_,/;Ru/Z"_e:t*`՞ө,&.X*Һ m $oo٧[ _j_|WieQR[k?EU%T9cV{0'ckq6_ckyf O ^UjciE/yK0~)bg RSO'ϲ~3ΧWW+˲܊'ҫR!8agFajB 澄( C~m|\un|~a~'7pT$c2sVt0\TTOh [x #OxOu R_J˭ݧOMGXd@ 쮓Y- ,S,Kv d]N|ʥu-e4Cb,M x=\uqP)f9+0;,-*UUZ5t&+rxxQ5>=2YVONvI#c qF7^I.~ĊҎYal,Èpk8,4h7&7+SϬM|/ ?g^OG 3|+1vrK]=G_ŕ0vRu:ͤ9T~)~{c xPJ2J:9ZRTK_X6j0u|{|Am_:Um4 Th eդW|>$44溋W,ta*VX9e; *0x9=j\_i,X:Td >x_8jZҜq|[2}U:INL ^8ƴjև5'X[~~|xƣI`f.9s8ׯ}br*XztqU6px/˸s. qmq],W4  ^"2OB>KsQ[Ee{/GnӈZ!C d-eD(©TXj3uhSrTp66{O5G2\V&V uF˼Pa.ZZYO:EyPqû|/}R/.W$wK|~$|c]\̟o|3% fl@Қ@5qOHԗQr,4Gu\ɘg:-U5dYikݩ=IZ)ɠsmu 8|]m8oc~^\}=u71n9 S<&6|{OF 1Ua3BbڷQCtԥV*T\p9,Yl4qtsWu#yI96\`}:)%ӭ~JP@?=gNcaxh6|mZ3SV}k q SkJm+4_-9S>Y:Xe^U#Rq4}*BHM8բVz7=*fFRNl&&&4a[ QBjnV F9ӪWNhW kŸ/'-˗~/OxþMJӭWZwAJe¹mjج"rQNha2 :<ӣ[-WR `*e/n /F:8M^$RJqf'RmPˣRV*y N4㎔!/_% +~nC]KxCRk+MVӡfH.M>h?[taakid[e6(OTӔ^Ip\3.<:JkVͱտ<0q%(7_R5YB!QNĞ׌kx=sxI4kisK{myoowo@MOYbG^ |>&1"DaRaV0 aR1R Vz5{Z֥RjpF]:5)UpNjQ[I4CϷt? umz.,MtDoٞFeg,"C;9f&|kĉHtU-#vMeew{j>> ia00K S.̡P9;/J?iJNf%ӯ5%O iAkO K8QNRن 3UTjbjNPup(URp{ᯅW'źOC֧⟉<3|#?fф:'Yi/.5y5=ZK-n4 \OpfKTe\=y^]<[,†k:(קGAQĬ.x9qJ*C2p5'fxya`nY#c% ny)p_3*t|LZ3u트%bi,O%@K~]S*xz*`#K*f_B&%(SԥLD!)B55ʣ(auaWի%JVN8j%RiT)8C邀 ( (?( ( (?;h%O7[Cǿx:mC&{oYSRƖi**TԯꟅ ~ ?.W|:T!ץ~&X67W!/_|ijv5ܰ sW.:fZMfT8 }hXV&gecQ)UqQrmMKypx)*JU* UB:† :0JQFiRPz.Z7G .?R?C^.n5=>M4+;|4K$x_Qk?SK򷫇b> 0S <=Zv&4C $k j4~#lg4e?S3hc3S15C.\'BUi)W,1*N; MB>]֖yYf3d`[:̰.SyVEb*W\ӈ)Ɩ[14eKW5Pko~x⾳a57xC6lE&[ O4KgFt2^OVKG(`p$RKVU3<^JU+>aT > ]~p9]l`08\9ُ̰ftFtkCgTxzp3 +xV >8 ןEy'P@q?ğ>2&?fOP}|j|<~+N> xúXj"׺ YlqWm 7xiӄKK 8S*'asiӥMYʽH` k ]|(0<b ]O<6Y`uKKPU]_ޣӘS} _N߁vz6 ׄ#'kD>ujakIW*Xj6w;TL.\3˟Wr<=9W*\떬6Ş;wb*EcLkcNJPBCݶN<҄QpCE 1QE8P"* ~9ʤRrr)RmRնm[1F*"EF+_$?Y]Ѻ| ?9p/ohi~8t_qkw~^Om"ȨԳχ3 (Lu.y{ 1Tk 0a:X4hciʶ:XTkfU _'p&U? w g}\Y-K.VeI`u02S))Ὕe^ x'~~ɾ !|Ufs-{Ohz[xG!]7Fu|#{#qo;fb a{i]+V.=Ux\: $ncag.ohY_#ZzՇ"Sxtۻy ޜu_E"<+WjR|<6]U䒜|.'pup_,i+|LU,m>bjvkaҟ,y%&+=@ 6@jc6vnSWM|Z@x49XndG6hV b*MUK tkJ{B \MJ~ﱍE'H2wt},%*{LV+/A-2t=QBwN)%|GҼoE ]i1[^ZJT-Avxپ9iգ^sh<)ܒC+ѯ'Qz+ЮjUV6NGd񒣈kֆksR8Veaӊ歅;VGȟLxǫi>x^uegk96 WӬ¼ 9eRqቧ:2ఘ,UyFq}zU 4z3X|<]i(S˹է_FJpsH/]CIJ? Sg:_-_~-EWixv ^)MƓa&>} bZ;Giu#,8wx“Zu%n1q>{C(էgx s}K 3̲F#7NsK QCNL:%^URխKMR?MW;\w>i?tk ĭZGn''oꚦa {X`e[dNլb^̒!JXz9_iaxle aJT`ƕuj2YOPB<9WөfxҔ(cJ-Pq*iåB5գ$)VF@P\!~Nf!U~гޤI$$ǵyA"=lG/L|% Ş Ws -8 |c&IUk9slϼZ)&>C;ox;OOJ5i9*Np 4zpu3 Jpil8*ZIB9BuFΛ(*t<>1kdƲmUx vng(-u+ o%0?^50^+ZjUA(^SQgI7WVvJ2\]9Tjpf+U{Wk:fxFC xn>{OXOh#{KhA&t["W}b1:Fѣ U%6<ʜTMFI18zWSMK8PaJ8W,2|qδ%jTڛgz_w3zoC~,Mo9ރm 0_XKu+'$:+ Psqdn&p-e P9FaS Q,4ak +_Z51Y]'Sf5iԡڮZ8ΝyBup+)K)'_>x>g?~"~ h|MמazxW umbT]֮_ҩgn N1Wx ƕ 8lL%N)s'*Qfs᲼uIU9RN*xRU%_3"I]}w^=J:!J8e)wY|*kEx%0MI8(R<6[&KcT!*t1pdaR^“IgK|岲Q]\Lc8V:Zi\vdNsaFSڄ#)8ҍԨQj!JIΥI()%y4'eL 7~ؿ9xxҞ #ZVu -Nu{mAҤ71] ɟj*Q)\.UWqrso.Qu"+Mst6~Sx~y񅯊~ hQ O[S G.ix^??Z֗u$E.FzOڝ­L41dc5z;EqO2sr'Ztg84{$.GeNZq(J[%̩4<=JPC587V^2_ƿxDʇYH6j<]e/4^0W;9R/VgWkA>IUyanS`kJhIFp<*t*l ~OFn QG KN.p9߳rIǙr8OrUlxa :yΒ'{XŦ\9mOS,¿LV$N1MF+?TFU<=RѺJ(N7(cLSʩ5JZp+X,<~ \i4( !eOMWrI ?$+I\TaRKm[i%ջ+e&噜&8 KvIE&n&ݑ=Cƹ<1_bx,W.Oi-!ꯟM}馶iώi? '|?7㟈o%Qh[ZM.Ϳ˭'F]GS]?K}wPT[M=gDO>? _4ť^3SSXjT18u9=UUiBM׈2|UquWԲN8kRR4c0ԡWҜrrpl/ ~D*<%cx+N=WEooGe}[ĖŢxgI/V{ao=ZǛf*r GG +b>>niT180ƵUze|SَC#,4J+Ԧy' 1*sg㔥9KZ]<,y15~4Ei_>xK3ZHi.)E.=Ui-7ve=D^n丹(qW W#U箖5aW:Yl]¬uckՆ_J%ӕZrǁq.:^#Oks DN V\5|eZ3\،Y`![c'oߴ{=j~9 xGŸcq%t+Vma|E-ց&n p]k|n0qWf}Lg[8:}F*O곞a(cZQe]\LuT Uƍ%3xXʫGj,3F DV՗tOwYV]˻)e9`c'i#!I)+6Ǻ¹|pܚQ9~KƒD #uuMuQ_Fkg8nS>0 x3-|?O iu4iV]HOq/6-MC,Αf<[ZTRV(Ӆ*PVZժӣF(NZ:pQNZ:T(׫RqJ FuTPF u*թ7S NRSğ'j߁ gw@}hQ}C}S:YxNQ`ӬfZOy\Iɸ~yOOW*Nr2דy/ThT'JpОR3>{ NidV]cNSu||aJ8ҦIPwE(ՄuO]į4G#Z'v\^47\)>,Pk),hڤL.ﬞ+K7VY%2_flD́L#Z*xWUr:*U?FIc1uӡR.1B*U骕0t4ߵ*jԧ?ˏ"ڗAӮk:?s9uMԯ(X67 ,m퇄.u`D?%aĚ E\ehFi(:s|<'˅aQ F?1կ#/ Jd.ux^h*u*b0, VUu*}f+*Q^Zh`mUr8~l:i?ekXWV3̗MڶoyiM8ηƶꖾl׷\SX0Pᬿ 2jq3 s_ ʕ\%$ርRڋ`8on(g7\Gd9=,73,Sn剝ΎmTXS~4O<_tM?~r>*{=cY .mscw>amcTחޥkwk eo9Y&40vc0qp!U〧J*|.O <(aJ }/|?CG8Vn#&8~e<^W.1Xe:T0LF::xEJ򩈅Zjb%ujP@|e!boD¶ԆI]تܳw'9_%1?6ojS#YԽb٨QᡐAX0<upA[  M~ |4fN;̓^=C^~c/gwuixoaq}b"gGV'qsIecWok?7 `q+&b#W3PxNFjP2N1(ƍZmc*TkRh5Pˈ2l0rK go0ҍYiN) N&\6*t)q4ZgKτ>2MUT/OxIIBWҴ%eV*3s*byak_ RTq5(b3; ZX>eAԩEO>:.JpÙB TUV*⟅%Be|&;&jM洣t'?mYb ε)BmM{?COKQ ׵MHsY[|;j2g0Ny^$x#E#?-|- Y.p\cm%6pӭ5ۛ˛k;;+ K˹ᶵyR7|1xg׎R9RHRS ')iZ9r3O(`جf&hxjMY_ JuTi^RqNMBJ)u%Kۃ|xKzoltxrVl|1LnuRTgSѮ|K>{䣀p\:rJYaNfxyc!YB:ԧOiOK\*qZ:'8Sg ?_0Li4>xOŧO"I^fi/uͥY(%f %GѓOV e^0q<W# Kƞ&u 2qO=F|G$=8,Cq j8Sx<r9Y^?5cq9w UeNPJE,fCJk'gI~6Cxx³5~o\hd].$z_`_`6G|K g?Q̲ar8ќ„^-l&b,. l3˕ cW2&S<U̲`^q C 4βcNxuN:4XXڕ}/?c ^<'z'$/ @i藌׺fҬCiihɧ:ʼayqYGVa,!&?W_??gKoO?>t?k}Fݫ"wO%~մMR5K>;zXl9eЄgK ƌ la3iapP`a\O/)2G(eKfe\pѧ'|ECLTյ iSXX[I/mN6uΡY۫K2 sl `jnNjuXQ9BZZ'R*4_ZZ`؜n7K Щs,>RJgVohӣB\F"k*ң?߶oPٺu|!}qx>ޜ]׈eFu+dՠQ]:/6oVڷM BW_Xl&&hEz N JxFgrα|Wu~3N/ZP2Z |7W SGI…jٶgO *gWZδ2EZF_73~?^k>0񯉴 {zVa}uo'"|}*\&QɰZ" غXgU8V?k*PWk_cf{$um;mmVӦ}]:O^P|7u}E}crS'u-Qi?a4mcö}{mg2\8\Ѓg9?59Tqx WzV8*sF 1yJ5^bq7 WƤu |[ *tkgx*.\~ gN~/3 [oh~ֶVmo?44k=nS4ջM!MIKh8}a28Y/+SSw 5+1l9R˱pqgZ0f!7aG[狧Nt9lkB&okeV%^_<+'/-_4h~,3߁Z+xJ[9ٖ9Ddg-e-vi`~6kS|)EVO y.oj*xvsy* ωrm`|5UJx<>&N8G1T2vRbr6}m#ⷄ֛ᦓR>$cؚM-†FWRNȼ#h#qVgN* S?Z'Zv|? &4եN Sh¤ᧉ8*9O3SdB8<(,U9uԣ# M[;Ÿtm4k|@&EJwƕlog,-ŅNW wҡd,w0S*9v] U%J bUQuχѣcӆx[01|^|ETLqqT^_f>*u/.[;RVX<* AҧpX,'(yQf|g6xܯ Y/7TˈlDiQ)QJ5~? (< QcF4xfͥDcmO]f4VIֵP#=^i] KNY8|qʪNV0JX]Tћ9[f9"8LFXf*z4bW,nz' \-CGw%>UXai„i`GߔP@P@( ( ( Y|X/OK:wm[rL4/m Nj}k>Mq,q/ pYbiٞm,:|1X ?cC2pؤ`eLc_JRRW[?֚G|>O5ú429K8Ӡ74dWyݽ3fَm^Uq\фiê%8a 8l57z4tӧNcF'ezʲ\T J*1q)1W9εYS/ǿE?>;~2?<[?x_'2&?fOP}5/ž 5M|QоfOB.|-j'G3{WV.A5˪"a(`)POSSK yT%jU[R5\V"lN&U1T}q6ms¾gfUl^7ȧRqi0JУF!JJ FSBoOS}i:&^fj jVY+j48_.hMtyt42Ne򬶋`)b+bC֭lF"j"ZӕJX<44(&qwqgX-α9+.}K WO IҠ:lEzKW%/רҌ0h38kw!JR2BJOѯ NZqxLD=9{)Js"zRf9I¹O/YnyN" ֪'1g:m*/k>,c?O$ _E࿉>/Okwq>b]]#Ӫ);),]8u*t—O8WeX98f;[8s*q.1 /YQGS}fV iSaaC>NOO%Z^=wZKsv:q\-Ov*Xl6 LjK *R,rRu+W7*؜EZDb+U?!7Cbsl+1''(QN 4pZ.rT0jTpxƅ(E^Z0P@gMM}w}QuF55_ Etˁ-Đausc]\Kafg쒯KNuhb)F"IҩOqjBKTerԊuY*5ӌ*<V*tjs(JQi8ԂgդU pd_>k?>'l6ߌ><> .h9*:H7hVrj>]z\uScT)Q<\TqUJ"~'UJ0V%)B2#Ӧƍ:+UЩVrJP権ߖuӛ_hHSN'["}VmgZM/՛EԴ4߰S7zE7vS")>cAx-էZ wRTҌ:EMV*Z)J_V2M7)BzPZi+E:s(o>=^ŸM#Y/uM#U4x_Ě`iu&LG@n Tu(sӯI*kW ʝ9RBJZBJMRN5(TI\:U*nTkU?8>=_B'HOߍ>3xYN_Sh-!u}bDKUYѥF\JbaN?YޥIjsIBj~ΌBTJHʛ jʌ+NZ8i0BU_gsSSjԩVS~5|5a:yYmn涿ӵ 9.,u-:{KPZ:ꟴJFkJJ*9&d:RJjFtjV'*u"e ,$$7M¤)ՃJp~ka?o|QXx P*RG   c8ӭqeeIuүV&8?kMC1Y)UN֩R0*>VF*F 5#Vo*p|*+ V1\VRQrrRR)ҕ*թ( )4d$ԢOFwM5Mk:6['/ -|8aG> q˝EԬZ,MU-XJ(CR?ZRwNj|0柴PrJ\s\iƕ8jTļr*8g(]Eֿ<=\M[^gI,tDt/'Xz1ҔwTatSjQQaTxV4勔ygKR>Օy9ԝYN:ug7Q)w/.|7[eּK_:)>uk$H_&0/LJTK T0aT)s)4dN4Bi֩ T:((`ڸu8V=jT)K҇-8ufV!~ߌm_Ok|⟉|Ꚏկ5M$ &=LdwI$r&$pܔpiatl:Y}w))*Q:tӋ1NRtpzpugm* KoAƙ-P<%JշN5K;ɐ B.^—gN!.iNPuQq):P'!抜T6}(Z'ZTc˛ T)TITg )B6SSi~̟|IxCšΑvf7+)k/_{Q߇iTe%$ )M{iק:Uya+29ߖ1t4jUJ5O&D k*oƺj]GTb|[SQc9oWgCn@6. ZGnP%)9JP$\Q6Uov$Ҍ۔Tye%vӕ'ˢ|߇~w{HЮ&eږxxnS[5ֹ{m} Υ"AlfX`HV&+Aa **+rPZ**Vu!YMU.WNq)xT*wsFӔa>hEF4)/gms|!N}V\MRֵ.5mB;hn?j:w NM!Q(_ ?bO٣Ot|'_L7gįveּoxZ[+[線+`. *S(֠ҧ*իҍb(⤨TO 9WӔ:{Zn^'F*3,aʽ5C3ͣia]LF^qְRFw^:L7~ ox}C\F6j>nꖺ>4NYu ,kv4٥Ŵ`0t3WҢ<$/;5J4s{9Pi{gMPeGzy|i+䘧'9֧lK%5iC[N&5SW91~_ >:'ދ~"uu][_{ww?|e{/]R0]ɦ_4V^\ImnapE,kBKWbFq Нl<8֮ DkуV:q.xvuB  U׌aC|;:XITקBJ!U=?CfE돉?~ xX[E'>'Kg(k3&mqivY]_YjgqZ`u\ҍ7S5O3NUy8ң9{#OT)Ѕ*կFEFjs|/'U2ϗl~iԵ5*pӤTtN§J"qu {x-g \-ʒI S#G Ix扊1 $N!F5upxlFb֌*T9R SV֥' 5 ~9iH:u'J:U)N5 c$ )E8&q{4hVo&oUq\#|BE2xG4,zWH#E #F5 +ȇ dJ<$֜9WB8ʴq*s;߃pڗU1c_Wb"ቯU0tڕ7 MLu乩U\Xrt7º_..FRյm{PK 6;KDֵOZnVQf5]FPpffwo~sI9IvIsIe9Z󜛝I:)KpxJ - UX|58ҢWp1|UZrv.Y55'HP@bW<=x[\}zNY:w6Ke{]jl[O*E_Y9Y.EahhTb#9QΡV IqB*jQN^wMR'~ZR,rUϖqjp,-H8(1E/'ySH_]^u \DOUX&[Ֆ"t G2hTu%NwuNJ ևKps/xn+Oó_ /Mg×|Ok^jמ#xI./KD,.Af8&kю#pT=Iet*eUb,E?ԫ~L[kb+M*Օ|Mj+SsU:tҦNNyj>ѼU u=>=sQFR4]N{GѦӴY0PE.եK 04cB^k,*K FҪJX:qvpRҜ'|*X6yOyvQcYm_ԩS`aYpRV5`aJASTe(Dg9τW<)M+ÿ uMX֧]"}JjZ_,%5SWe3} Z]~w+pD=to ֕*Qº5+Njϑ֭VZ+U$ r<PUVRlDLM?S"S '['a&7k{O]׾"x$}FI 9_[Xn!3>_[Sqѣ*b(b*ZuSst윩3VSreW1ֱؗZXclf+Rb(9_srS>( i9}׮_t}Htec_I𸺷^|q=b85Jq^~%Vj85:4+z(ХJ2=Y)VVsTo,40fl4SSULU ."1#_Fu*0c~Lj>x#T_il>&Vڔ_4>' Cyq%%(TRyĽ SJJJbkҍmGJziPF88֬ɕpw䘊xW:Nf9uiΔuq0Ԝ}Jjqٷ3x_||dxsokab#ԡe-H<=ūEdZ]C[6[x ,E8zR9a RZэ7ž7Я|?[Kevlce-wE*nͲ&uc9a~~Τk`t1Zbj29*BP/V*x>/ Z>rU>iG3 -\.<jSjiJrJ|H)w_~xS5x6IM_PUԜ:qy}*fSԯ.Yb h Kx-K mJsS斗pCpWC'R<=\Uh*Z3[^RWJ]|SExb7oP~t>׭[tmPHg6CWP ~S*5UZ8ܾ%Y*T':TjJ0؎U_ K|'3캶U`NUs%z<F)SCMN5VHNT+b0؜Ek0=V_Kψ>)hѼ9=$ºVVM/Ff21-tѫԶj 5MEnL#B6ak_:-Uy<=eZK :'B5'x^ hcy.mc2sG/MRR" ue)}ueRS (cƞ> x[[gmn=+&km;Z;{5HmsQu6]ѩ:fgrYYr0x|~**zQb0=KEZ+$QQB֍J3 EHFE p؜%eJ ] jiգQѫ5N½ աRhBq3?b@>jC^w?#~6}gjiw{l<¤yk%':8Iћrn,f:V^1Qo^_R4d/U]Z_[g3sB*֥>,7 x^UsZxfZƹMJI %ķz,P[\mn;"]D]NaL%<>aGpBQYrmV(Vs9JMb%WJyNW[&Tg<B#\>>58ձnuz5tjҝ:r_?+f7ͮ.%亶6qŪ˨_I6q.wy$3¬.1{߄ Cmc-j6c\l8D S1˱Y:aN8i/n2vVڤ(> p9IByj`l0^ڭIU*jU V`~EqP%>gt/;Y:oK;XwV`qs}{q,ךw<}/kx.799A ; *JSqQr ꐣ ITFz.VT~U_<57~ھj2~0񗍮ͭ|A]b+iaH-by_rTaп¥:<ԩW[?i^|իUjz*Fc(ѥJ=̣$˲:5eb+,EHq`hQESaN%KI*e |U%VZgP@|4>#}[ծgqo/ď:>$:Z1i\][b/WG[c[p x1x؜Nzѯ?iJ 5|?= phRKU9ydA*o7VƖEEc 6t)kc)L&*REZVUNFo?kcxBl/Զ_u +mJ[y ZdžڔZDz*Gt<^_]_¥%Zե b15FJZ~J|#N\kVSʸ;rLET%5{I8 5|oKIw._m'F#mc;i-g/ŢJ`</2`ޚU/SS䔥J5Lst!NU'IʣrYϻ67:W8quQ&j V.?׭FuNU Ta o߲ߎz燼e'[#F-)O5߇*N-n4|y|J)yg!ܝ#s ZcMmqui-Z\C/F/+0NaWAJ9QçZ~% *s q8>cfcc:ʚ,_TisW2p9k|fs<=/:އ0mO|Q?Y~Ş 'Ocj-_&08,|{ &z}O B^ag eۜ^|p#/5j<RQ-J8P~rk,_e݆O5^"|/,$5x]ncyaClu .%k[e\|FxU?c1jqը)Ub*8tU„%Nt!N1pWGqUs,u_W9qYrYSUe׫\5Z.jfNu/k` (~3|_A" x2QisAߨiRQƭ`qߤ2+4r^fgp̰/T֥qO TTR4-U˗08, ܧ11F3*6>} 0oJ$p'/W]cy? ?ο})}+|X~ڗÝ;P-Ekx6UӖ F}VϬIMF`c[Ko+ަgs<6e*_ 0It熎Y[tQ:ѕ,?SN~|Fu]X׮NȰ9^`!1t+bqn:g]q<6E]TbaJtB1;׀4 <_ZlW[vu[5'MFMJWu bwWJvO+/LP_:g 9R,$BTt Z%MIkW[VVsLxH#^XRZue%1UN!RYNRta0bGR/=冗PxTnz/u_;m+ڭZZZ[M-@-( ꒭K 3bqx5TNhWVR:jB#,4U#q>~*.Oc)c~7q^Nt#SPFg':TХsS)»xZhpkI4=?T-m&-AlR(M1BX6K:&4<.aB+QRNX'}]xgI%a%J儝*SʜSq6G-`ra~,5hN02VxTE:+ƥEYMN|[+bu-*_ږc{xkV+V=]Nz{[&2_,k ^Up(%aB8،m:pr,UZBq,)6:e_U*xmzW}gM+sOp{~A_#\7V[gLJ?]zKRc_]kN=Z(rf/)qxb^9(O۽hM+T𮱤hm?"9hlq\9c1Ml+%Jz4 0(F6)ž#thSKQl|B=῀3s <i[7z}/ fi%-Ym{i4j1뫨^]_{wi3ixWNt:0Ft:P\*Μs~\3K" .S$! xS{9ʥ:<]:VVh]6jv!7:\]\\K. a0ahBsB`)t0~ZTiHʔ oȲ'0pe5px\$'UL.eFםIeWK]OJ+B:۳vŝ3[g漿[!W|C/+Ze{m}w|}O٫fZ΋w^ [8ͪxNHmZFJO\Z50yB86'(΅<'M½*pT"cqs)Nre=L_B9=IbeW/s^/k&%SìB|W^*nEx_={]/TM.r^~l>"Sׅ*tak!7O**8ZC S4ͫa)N9Ыyg*p~u}iikakmccmoeeeo 1Zư[[©D0ĉQ*^:JJ%)s9iNr)JMIsRB*)SB8RF#N*TN*pJӄT!($X4 ( ( ( ( ( oο>(|U#4OU/|uPy/ÑxKz5Oxz :i5;XӍڭGQ2['_b\V"8JjTM*xƲf9uկ*VnwSNj٦OG1xE(J1K <5:tib+CoV5DP@P+IϏQ>*GfNn+#Raq<5x^6am| [6S<&.<6' V~><-n:ï _|:]Ե;f -+hm"tƕEcc_Iik_[9.kly U)ʕzrc(F8,E9Y_^e<.+ R<6&X"x]|_wD[}:]Ht '|m?y/~_o089&8:P!XLVJ0(1ХRqZ+VNp}"<>1p fU2YLx0XLV=s<)<k2uaAUbgjٷ %?\"|5")ugMWUmy{.^+d_XkWXD_$ٖ'W!erbܧS R[NU*• 0+*x,D|wpoW Y?Sx>U2ViUNX< 4*`̱Ԫ8>UR%/6~'ǭ#F|oo4oX%? x9ೞ/|SU-NgMWG&u^s/5α 6ylTʲԅIP*pRx/gZfp|CQ(Ok:}JWK2xUYF게%:ս Ӎ<pؚe UuiSDznpg\9p,>MX ,iWѣIf4)/N%ZZk N>X(1fo+cr~:*gY],v5*4E\.aK `꧅21X|MNx5Ia$$?h=CNi?~1xSMX \$wĚ߈|S{$vOZ[\Dj&FC1my"K(3mI0عTO3 aR71ReFp*x<67#?q=UeG2lG2$TU|vvQBugSrT?mk'@<'-(5 71q^CƸJ| ezpjTq_P,M,vR`ҭBh0\R׸~NP@|A Wǟ_ZO'Ǿk7ŸKyx!<;Nf{]?Z6ڜq< 3VA˜lʞIC.a T[=o |hҟ?^x>Ygm%Cl5KSOӭ.V{89'3 "LZXkK,-wG:5<.&u_WbN+!^gYgp>qr'Ͳ>_da 6g5eGVG΍Ʈ_)^I)|!{A⦯}ogk]O&%φ/c7NJ4KmBY\Agq6ag~WU,~aO {,V[˪ҡQU_ .iӡ֣)%W <2>\] q01U'KKGʱJeNZxTߴ74O^1Z|~H"I hjz>[5MwsK_G ;^#Y>.Sʩp+SWpX&=<^iԥxʿpwĸ(bHe? c (X<43'9S ^/*pu\&uJ8W7}OR//]is$holnN xopx[<*U79No ~ΚXUaN_M7fNQR,.ż&<J*k[ Eĩai~i+QПS}P <{Ex3~ռUmZXZ>g-ZG-E O{Bಳ{4d~+3M e.^_iRJR#*EJXzZ8FힶCf\KyOC9q*.p WT*8Чk֔hBzӍ(NqWqm|a='5WV.u'Ǎ0JT5.Goxzmlt GU.E][{U ?d)^[O7 ֩QkP{Z̽8|Ff8: 1G({9ʓJ5)զQSa4k1TR(bpcF&"a™q&k(RrRte*\M0YBaRMIX|U*8=jg#˰wqYVS\%G YGָse6oIFK+1XZGj>>>[9~[A^ahuN5oY[&'|4~?L/^>t}BƟ !x-5?\!̖t=xK\w3$i;T({~ wB:TqZMկB3JtVRNQ8K^JUeW<;f>>˨Pbh<9rcVTR![FtRw-XI}VRO]|l3W?P<#jo/|5xGV[B=[vj:|7ҍN#E5<3⸅fUj&\xՕOmCB2ѕ,=UZXN.cR8)QQS09~o⇄yG`B*ynYJN]WC5γ 0'ᇅe[-O7Wxv+{6_iD&cq4ikVeRXYc[Cbq4':WSaJT%Aʓ*WOظ:QY}z>CO9ap5N1oG4IEOcEU~~>>|k.TW>y><_ ]_0Ϣx|xP@,u u{($6q|r5<=,aZyCd0.Z cMbjׅ*Tr1_¸&ΞSK.-0?;_3^U<( Ix~:_|C_>7|]k xᇇZKsi:zXC<0kZ-؞+0S媜1XѨՔyp8GW7)N)EүMJr㾩"4ps:<-%Xת*th*j1֤D)UG?j/?f_'/_xj_6oIx{ Cxu-3OmoGu|VfP݋XZ t1oXcIΖ;-u18Λl%USAO MkJ\jUpZX0q4TT[T :2Pe:f(,>k?K׿~:|ZO}Nhܭ!F<7qVK)lu^Oӵ}WM΃[T(K^|l0QթʥVYaBSt9 pTqZUT'bRoaJqx%*tLF1T:Uc/>j"4O7>/jxg~Ě׆3Y k@ѯ-#iKO[\%XExwT]Hhv20i:ƬҧR`xs՝|K,JSQCJS8U D5'UQnT Nx:x`@j |-T7|@ӵJޡ+o ggS񿍵-u+MFO'P5۫[%xW~7)FZa*N'N4(E MSGٺ<>++,I/kѡTcR|hSRԧ)ҥBW*moo?S#54O_x>se #^еtӅݵxMGz=>VQcT,>>yjJ5B*:!I8|E\3 Řb|68jsP„g;{-7NI`U t*nXh^l^&8J.R*4)$ׯV\ӻQNRwI4RS^*TF .ڳ)1MiZ6'/|{~Gc k^rxl-jnc ;9Uڥnſ0e|&({>:u 9*Py] C 7I5Kq5ơy-%-p!pYp5U0byWԦiO*pPe+6џxr6XХ9T51X8ZsQr3֓IjO>IGx@~ |LNڭ|Tßg[ַ{%<6:_7q2i֩j<^7zT uz0 W%B"+0SʪB44ዝ_fw< 0%ZX|FkbgkPz18|V{S??Ŀ<CMOU;/>VGÝGWtNĞ5)-o +-WQ\uΖ43lj : ڬiK.jCUlWU)U^8zlM\lSѯbg4Lׅq]./ʲ>SJ*9OpxNc0X,E8ц"zvh<7,T0l!~+- U|{x6'=KI|=MK"Nץsgk%:Cɪ| ۈ#̣,,Tnctsl/WSu_ZFgZԱ5XfgNd DQO?IԔx1&_pF53Ib]}a@P#[ZϋxEмS>-v=Z,70˧ )mM7e',N'sfGO ,]CJxiRr⚞ <^4OSJUgG ̃f8 X+O5Trغiі')OcPS #*u}[> 9?_/h:޳q b{"lv6H֧KmiXռX×_/9]_2ŪEҧ 4T|N'V|.:t#V(JZT)\EZT!VsZ'>qx &LN&J+TT)N~ʍ:ѥR |?3Ѿ|yӿe_vg+ /kruWM=ׁmu֮|;czŊ4mMR/m|?Ͳ .*8ƥZ\i2', %a}Sa!S] _[ܻ.\A`g5Z8L& /p@NW[ m0Xr}]O ^_08(PˣQ1YcQ|Ejܩ |1a\"CF^2r>;,^|0'>+jqgj:^ex{zMG\eSω=R?u_34Gc< (a!*ܯW4Ц( x}? kz$[>OT kWR^"h$`/x' W {l}l& *UsBxu Ia"Fج'$C!çZPs Ie[`a41C0/eKRuӣRz8 Lg7|RԾ7|SoXtMSt_i:dXX\j[ g^U_* ''ex<}Jk{Ɣ2 =eRm~{Ww/ajce SHSXl57(a9]i9I+Sᯎ/ 8kڥǀ>Sʖs_Lֵ"5@4Ԯl,9U|o2J8Z97 \pҧCХb5%8R tf4|d2L'p9}l㈳p9}: LD*faR3 0XLuXQG uRyVC¿BkiOxVu|_uFƫ}oqwgl4NWni1XZLcAElkFjUZ,>.|-jr䧗c}w.s2߆,{0dU3|] ,1?Ys\V[:z8N9eň\$WKGU_+hz&*Kloy]EbqxL4Wkdc+ƕGC Iԯ]ӔiFN,5'K4}ZN4oTKfK:-M MF;/n!pB$!JzVV 5{zQ:MʟSrnPm& _Xel./x:U)\*#WFRQ4k(WΞ+8{Jҝ 4hr#9ӧ,N"V':?#o|rw='\? |mϊh^9u]Mx¤T%J:X硉KN8~gwX\,9aq*I´=#^:\M;B ':j%jh֖ě_ ]7.OK{v}nMcCmݴtӭx.F2rlkRgGXOѧ4.'T\#:r˧QB>_iO2&|"[P/}~4lk=>u+Yg^0I/^4V&1'8qUNJIAIo9Lr<(PeX¥nRJx5:/y.v\vZg)zEqw_o/Gp?5 7 kž#?:Ci<3Pts^IFh>C5X|8湮adXTdC71sOG.^\ Sƹ:e sibp2n8 ޾W/03c ٲ/5  %i&MӭHRU t*Ѧnu hZhEs ճ\kU7N<>0'R4a:TJ'V=s1UaUF#bqL/aԥVGFu*IB SF^=*S?s>jcAfIY<^wۧcmEZ>kilGX[XƩĸ̞ɪ5014c:U+`Uէj:U*VZ e.LV[\|I1y>a_ Tp_ NoC U,Lpm,\L'"(b)QW潫0_mٛLo~ Ҵ [_: oiC MBUHKէo`n.b3 j׾PSqO -z~jPRxtkRʞg ’5^rZXWTSTrWZTfB!JLd0aU/o!j~$xÚ/?G_mo Z2zu!HoMt[kY*q\K!' x_K8aJ~Z>0xZ<-ZzX/E Y#|e ҌNzWx•*/B 2eXIbq_<#585 xDGV8Q8oUXHb8慘4i*:/V*gJnpTjU"Z5SFF)JjRJr%ey8˰Y_W` 5,Vn2:RQNJ3Znj5#kFt5!8G ( (( ( ( (b]YWh_7r?M?uAZN6?$( ('_ؓ1_F_Dyi/$ŸWA=ʹxg'ohr&Fwe%F|hEwݯ[(ՋQjPs8ݕ:15(ԋ9$v?RO8'GpSRʔ8݌(Jqh93'/ՅUΏB'(c;K[$KoO^U'ݺttx'5mvۓFZIF+h*1TQgm3 @ޞh skVK) Y/\ůҿs>5x4it 9i S\EK۳5Z$)okz\5`S#1ux2֦u8qN8i)`rL=:40,(Ы[a85`r*sW Qf\꺊Vs3EFn%_5ӫ9`μr5oG|Zf>W|e_w/|/? ɫx_ |>𷀼1xC^O5NY6'|-h\ɥimx򭃥W?ڹu+6 FuXپagգn)9S}#>nqr.p pYn/S ,{f7 p8JXL.AFY;0֮,5CKimEI<a|^ehiZֹoq-tSewf_o/#eپ2q]S/q6QW .">2 X8asj8ѦьsLia/ pQx|~<.^-! v.)+oNU'ࡈTjфq*Ժ@ (G.Gէ\Oqo٦\w I<1[ٔ,C^(I_>/ΥO|J)PSxSc/-,QNXY9N``TBaؼn&Prj6 NN.t_t~ǭﴍN wauo}RN~hZNpBgR\YZxN(AS?\>5 i?k߲ǟٳP<=m煴rş 5鶾ԗU@l4Io +HI[-:UJtWUh2"y%YGO TacV8|O6[ۡJzxc<=mm|mkpec0Ĵ:a2υjס b%q[K*q8z8\o3k ;gi!?|Iasv_aNqzK=SLE&{}gWyl{:ʹ~'-xUXb2~;,ͪ΅kib9N]ܫQ*5L=ɰYu0419]Jxln`PVQV:z8Z5ap7Ml~<#{]/[5_ oY>6_*k}cIi~C 83HQpb2 RrYajb{)P2~UЕyQB =9ka)qT^ ~|?ØM ׆qIJausJ q/HcH$X($q *2)Nr99NrnR)JNRmSRRI$J%I+$$T(?8?^)l.n-n5x[[ac >H>ywEs"O)Yߊ2Jzr'ͲH-&4U7fҩGROs$ Nq健)ק <RUp<=,U*5i˞=C ?dgeKbnjrKԒI$`,~$;%q&fܕΏ$vykaR 720mg{y㎟w5*@z^WiKeآ/ PTi\\񅓃e Uiy~Qbڪ2>s beyUCp~# Mٍ[犩)7t~s:DqͫxoqJbQτ}j9[dc{(ϖRNӌ78F[\MT^!ͱZvE, yQgRQwq8')gY.Ux!ʱ6iV֕G]jo>>!Fn$Mմ xo~ ?-3N44G~5 mm6:u\kwڎ!gKm{Fk0*8eY0qϲJRN chβN&l48hʴP#'V7!eb0|TrG e9](`y5}P@$Op?o{%uӾ[xn,[4+_?OHZ`=kr"|/U?/z\u,+r*|Ka8z%J8Z_X/}1ƨSiγ79)(ޫxIrJu!JN6?7hzzb|=Si7:6ȂDƠck3O!*G+Y۴0.9⇄=it(J :upѩNJQ*iUg~=`jo .Y%8T[է U)$i>[]~_|5f#ßt?| kf-ggX t4e"g%V[[]Coyw搦;ʫW=[Cjq7)T!GY`j>)as}3`qv>h`+Bt>c~ 5_(uK'ٵ? :gd'瘾 s#b2\ ˊpiS󪳔UW"_Ѝ%jy&Y-nnKYN4Vn0R(B6MS{e5sl.y#/l4=Ԟbdpmr *z3.)O;ΪRV^xY~[B4pXf8cgW?ƌa2WS+x a\f|cR 0(dx|Tr,x]2omַΑȿi`0i{l;[ ({JՇ4ehIŦu?rffwV2 iו8ex%YPӭunzUhQNp|[of~aV߳{.gԼ}ׂ4қ+úmpKY详FQ/sU,q'2"* _0'ͱ1Bh2U'R2\*kSC>ÎƼK#K253(,Tr\7lfaZPBk/oWXywzҿfnjӈ3|U0hWXx`XI_U|Ç1}Y3a?ɡ-Qf+|ތu28|`qHk%jg>1K|*?gx#Áo׶xºjW&nј ΕslM5}k:ϱye[B+-SM*ҡ&:өRR`3<,iM`e&o֡Sxg2y ,~Tp`*U[ 05o)N+ ֥8b>}^P@k%KG[jY{>#YD6ZM ` ⦯lVskψ񫛤d"ҌopQd/2ʩJ2KDPp]Ӝvni6_Q۹ڗ ɫi-u&W;yd*ZX/.&;;+^@8*%t*5gzj췴xMʳd g$ŊjWxu"jL5Ijs4H6?VC/i~?g ټ-Hw=!+_Tq lW-e5^Ijr-O7g׃oa>/>*xCR>׉`ۣkKi6̑v m')εJyW,4Oδ7MNZ¶mFU^άca!f#NJ<ا]ZTkSe8ө:}Ck*?_ٟG[g2r&>u.Gm=g#}-mmn%]8Kē.541GI×877Q:i>_ 3|D өV'3R,8X.iSR+\#O[V㇉> l?5xZtXOCӮUl5__FGӴM-B5ԴןvyV< $qrڮOUzP: Xؚ̳}Uu*ԧ*N9v<HMNIukB%BT!Jo*hSՑ+icDmfk4;K[P8L ҈[f,n#x^/k_{{j}/k[_K^ , >naFok{jj1P@YM~I2y!^.GODo)oK7opyX\&F԰Up6qTڜ \c\8z4XԖi佖[W~VQbៅ$Op OFBUNA_2JJRTWMIM=kF/)C-N2 (dRC$M4{^P|3Iiot,\K7sApԳ\o< .bg*VC)ʞ]iG_wnݵ-s(F7R!*Φ/律5$I*Z7vV>q5xvKOh= YMoM B^aC8K>kzm?M״#O_Bj :P%*Ui`*t:O ukЩNU)W^*^51ueVNu[nv2XԎ*1Tk*P㈫_7|iI|j:$9ӡ|M o7miREekfE՝giY_,W.ያʧVoTtMVT^0JP,M:xb!0"g[=0ٔk"NreKqharNN/xHW?g*my≛_~BK/[A+Ft9u[՞)u }-Z^\~#f|-*ԣqf,TN*VƤ#JtҠkWOӫIМo˰55S3#jRxaɇu*֒Nļ5֥B>| }T>4+|Oj=2w$q-ȳghֶ6$G=5冄hO``JRG =+Rr^^JI*pѡNUzTg%(<|F4`)?aF )*F+rZ7 (>3ɓ~_Mu?*ILO[Z'x0c5/~_e߳W 3W&Kd 9OYk ^~k?lkxVH_ ^ḯnM^u[E"MyD[;-0fyj')5Ԝ>JKtJReiB'/gu+JC峞|EKbc8w RXju'YJ*b}h¥QVu8WG?›Oxc^ noamk.5ev: xU7^[CXoLVr,Md<&WHeVl&24Z3OWb1b!j0XܿB0QO6"& .] s QS|Tfc_|{=||cD_?gUꇈ~ѿ|7K|oևx)nuo=j3 mm/V-xgK|&a!VKG oQIIN2R9+MIY]C9ʳ*fXYkNЌ 9N" ?z%;A=G7[<'znl|e+I}ksZ,V։omϗWIƹ,W/geNhT^O.V(apN+GCPy\?|9q+<#ͱ8(rС;a,N/ʨT,E|u 7?ccZ)tsUԵ++aӵFq[jvwqZϪ\XOivRE>e/5j|lҦ+ =܎//QxJUP'NJzO˫cpy5#81x,ej4)?6Mq: u1yV*8\.6`4g=?d/k"n5ͧoXG\]6vu/ K5ōܼrg^Ib?Y~]E,Fc9C 0>"8† Vԩs"x!aVS/38 <=NNJ4䥆Q,F3:x|<*? q;xC¶ߴ7txG5> *h/-4?2>ӧhjv.\Kexw<4W(Jx:~Q`z25F"9]\oOx HΤK<-8Vn.|/uclR^Jjsh:\S|5^0P@7LkU|?Jbmd;Gq{.cIa2_&[Y̬ Ƚs_]GgË+χZrAEOfH |Hĺɩ*I5ԶlZnsq.w #݉e\k<6?jTqV*]`1XBd75BV:؉]iS3Fṟy~]ΤgZ^3lf0f2ZT_ӭ:aK٪k#|C#7q,|3$ybsuq/c@hti62As{2p%S m3*d Sp>¬iK8k3λOJxi|>8lj^ʾSaqu)JPêp[QJ:8,6cVuB (j_g]B5]CH<5=:wye2&eXHCZ[6y~5w8\*jOYt\USFJpxlv!%ovS^G>}.jXLچ"T㈂<Γ*O8 5QuiǒsX~2F| D~~ZOmVՒ6eVpIeVMԝ:T15)N)}kf4RJUcKիC,48zVOf 9lFeG ^ЯC RFJXXjPVúN"XG˿Z A}|>Я6 xVۼٴ"uf7?q>"(:x#J^ҍ m"x QGwߐ@Ǧ1_ɺ?xlB(|aI%1 Qkwu:6:w|E{kmox~ѩⷖh'V9q8^l_Rr :^.*gcjn3mMP~G̶\C>!p˩fj,~x&&:؊T^L>EM*u(Τ7,6v|wJ{ob_< [=[? =m5}#^xnTgSk%Pxvg/bn,E \Wo ɸz3'5_^pO*ThΦ+(UkӥY*_p8Ü`iЅ-e:T~lN&b1XbjկVRRr[YP@\ \;^"ȟcğ1Eqg1z&7I_;eԊ'Apo9/^IGc{ eg2'[WW|Sh^!mk/IIeZyd Mc,6,SL3ַgu_8ٿaR9OWͦ0Wd~8԰^=cp]yMZ:t\+ QjҤ<攔$UD%hQ3F~.mOҼy övR#֦q V*ͣ?_\<:G]Nnh¶7 .q8lyClMN0G Y3Mg05k4bY>6~iBE(5!)>,C\ Ѽw¾AKP?XWwǞ+m29+ 79i4.k=CVռCiYsun͗q|COV23 Sʲ\:rգSU a8x}k4VV"<|[bxɔ|s fG0yxUszنgURy|G(:eK:oxω>_~ ~|BhBN~//Pƥj8o CS|Z{j,pnL0y>? TUP,QbTغX\EUOGqc!סKs <GYa( cX9b0FhƤaK4J8jX)F8A^`P@q)x_kZ߉<;gxN~x^k4SL\AX^YMa5E cC4W14D?;Ϟu-<;}{(uXT$G$u it٭[9䴖[fG^cJ8,"N˲+ZZY08&sξ%ʭgRTJN>e?aL[3y=e." M8⠮}8j*s q_Z9Ko|cvlOkB˴_-O ͌/~#I Xsڞ,` w2>!Wz7۰ú߂{آlž0k/:]jHK|Rx{s\OԫĸV{(F_g:8z7:NQG=4E׆GYV\JZn *x RJo^J8Q|@fm [//BR:jd>yǥDIauynʲKo ǣMHO2<AF i0\<^ iSpJ.T>Nur1r厏GY{U8ʞ$~(5;S "ӽ{[eFe췁UvpJQK~pfm51#wxMyE+(J+kZ?V ( ( ( ( ( gÝ=5o~9wS񟉴_ 8 Kn݅"ej՝Ji&էMFRqTFGթӕZq߻R MsD֝mիz9jt,ez9C⚄S哏q~o/C_ _3 q'? l'-޳]:ΛK^ܢ|1~ =~0 |C?ŏ kκ^jğPX_ [&M#Tc-6skI)5ʳ|?&0T8{-bTB0YH՝,:tP̩Yӟf7Nkuɳ /CWJfmbb(fY®T%Z8m,F {)Ԣӊ^7.y>)?PG|-=-35Ӽ/Sk#Ҥxk2KkO ]E[ڭ<_,'>}硅)XZUV1Y2BN7Ɏ1S#>>yʬ'pĘxI ԝ9Մq4^0jSj}V[PT1d}~m'Ob¯3,?X5Dzưhڲ躓[ū #^8W6QO:SO S11+FU*i:YQn\~_GQf?,˸f*/,N/JvXIΗU`O-_er?b?[g.њn_j6Zд*n9t߈d8䩖9K:T^`Q,gpy}{[ꕳQ~*VkM[6Mփx4%=6KKB]o kuǙQ˩i21y. a QƝL5ĩ.ܖp*f|)X9`n;\>c+Z5,/ΥT L.UKS'%v (v:wW&_ڷ|-,;@“*^[GJ^kW8vr8qNK NENP2 pIyeUҔ;GXWJ3/1b/'g:1[O#Lj)^"իYRɳLENHa'9/[Uc!iGuw>犼=xZ~ou N " ? Kcp4žq|ӧ,T2\էeqyuJ+9ԧ,FO IԩW =8OQGU~ ɼOCK? 0U1,>i^,qZx_6N¬Yiu| Pܟx]<am(5khKxE[u{+C[{걙dX֖cxt08^\^23H(e҄a9N1\}Gxq3^]nak1rUCSF+*U<,D*r'CߟY^xo_u-uBR|3x~!ӼC}iyy5֭- Nռv~OǼĕ)eq42lUy|aJjZ}S}! L)19|8ϸ5|6cqtl/*0,.:Raqؚ(+R+şiaZ_h.u/KM_(mnwcQű̷v=J|?ƝI{Q)BUUeYRF5*MP:p%`hxF2¾>$q |e)YUɘeRx:!B 8b%R+cߎfVUS & Jja\YS:\GaǦhv'ң +9RDvL]J|9|׾ҬR9/uxFO񞋡$:m&J%&"DFgy,':jndNRt •(^ZJZ% pIIS .O 0KV15C p2G O0x|0)8ܒ&(}c6Xz<AN]_ͬ)y= մ8 x:& Z˦i {ISQFIcP78?PsβHSŨү U)(g~04e n+Q q~ 3*~yUz-l5 ڬAOՍeqBErpJsL}G࿀fo_|n񵧎|{/XZ:A˱ntV[mu+3-i)n|[#YvuGcegy RIa\~0,j:v21ʷN*< \'̲LҌxC[ e)եFVӎeAJ1Q<aPiO%/ufƶ%@WSΟuoZ՝[Sk2{WL9^..g2|lEYՎYee73g8qU%l?/tOg7O4NJXt eNn"[bp_˪rg,ay, +U׭ν:uNU֦c-mAX~^8~2)÷qiڦxWZwtKKЏxn=F-?2Ai~ׯ_ N43,90Y 9`爆:%8C<- U!QE{XNO?*V Gx\0(Ss,0eX\ ̨ƦT|6cJ\0g=7oi_7Ý;"uۿ=/iE/wy_Eo$$E5Nx$gO&S|U59 >_e <=[R Ԅ(fUW' } KZ\Iyʫ' f'7֧siUtNxь$xkCH( $6m;p>._·~_mO_miu $qY>LZz}$xL7^V(҅dy& ?4.+5p>'*.%|U=xfX:եʩ{_d0b9mR,"?jQN5|WX4˄ 4+H|Zi[.K֏me SO pS. kc3ޢR,' >$o[~ hMhRU\Zi g*M.) ^#˨.[=sHaB,v&J_i#*ynU4G% \ͻ%v|fUiee>oixrG|E<$kw/4RJD۱Bb1^}U99ܫ1TiA;vJvJ|ʰ33L,3~Hϟ$.Qru{AW_'S:}gR<%=CS4D*.nh5y<)}biu'.z<]voW+MEA5Ofe|#GpeX|,0tٗNK_%)G]NqР ( {`VuMi=?h)>Ԯ|?j6hחځI^q }^3&%RyFaN.*u ei&< ٸadwOp7 : wײzؚTPRr:te<:IRFu+MS[B|&`>?-xT-? j <%^.5܍kya}`XPӮJYkcp(:R5{hTNY<]GRZqiÞy.\&3fPѦs:I^J8lf g5^qt+r|7G-]O5_ x?O_-%^ 5)ukK׸I`ۣjz}=m#|OS|~Q*X*t*B:X&YaFnG7PpuxJue\kC3^crZu\Fn#xz:GK.b'S+ԌMdO0&~ҼsiGtoEӯn"FּC{kqc^!Cq^CqmeyW#8a\=lN5TcZ0#Z1Fg8rI5.u6 #-WaRRj!_ Bj 0 Q?:M+Cܟc]cR5S&(d>ސ<#]_mdu<]J2e*8K py 3r8{kc❹Q䒜/fQgFx2,Vse<;RaQx 0NqbVrt!*_2>"Qyxxo\>7"&"̺3$G$E7 oC"Χ9Nc,܅OR:JR2,R9^eY#sR#(Spg{rI'%?emG? _m>'@[[+[/ Ah-NKA"jWf)"2e5¹gpxTeszuj ܩЧ_,6㇅ ^)ӟ7w<;d#bN)-ԝLŽu{NLۇq1/攧TqTpqY _|`~σ5g᷃QΪ%ͧȷQxS~m ֞"˦^^ x3?|:DA5K'ϳ\ ACKI2(byj*Z`~g<Բ,6 Fw{8RjPp*_4rq櫀Qr^'O/_ gټspC@kKic^.75 V6WVp+LZ7:xzY/ïpձ5%Sݦ_RuVI*X\,}Ez5RCZT儍J劧'i:j(AAK?kߊ #YZ(5%Hamŵ?ڝ\j:MuyZ.CBE}w֕̓O2+et+e[͡U*Si]aNVI*-ԣzsQO.#U/atqS\Лu1>NT^R I|'~hzƟ1PAu$0RcORcRc ҫ[1U(UU.z8V/J'4qPUNU`өCK CJEJ!Ia\'Չk+6海7Y-م ȁY!o敕6.]RzѠ*;sJmSsp{-YW ҵ^JtV78X8GaX|?A'VZyguI$h%^itOVV4/r%Ko,*|TSUV' ' 8)NX x\.>|k ^q?N0TSrX9|e_ٗWoֺk~4Iaod>Iea$i<>u-%TӮ 9Mgx9V_aƣbiÒu>fN_qs2R3>Vui*/mх|ExR?g\|N.*h4:PHդO/O=/|QT^7aCVQS.֔#Ž3<ч% ?گ`r.Sb!5C1RMZ̞OS<3)JU[Tz25hէΟdv| J5j>akAao{[oXʲ[[iM~{KXY΂#T{ITksJ4)\jQxj57*x-xTeY&ER<5IfNe'qJRSRհé/ς(~|fjPTgE5k;/@l4K,I\Tդ+&nuuYΦ Δ~&|I K#ڵĩ<">yQ]*q{7ÏJq<' J 7G3F-FuRnKpQ\4u(sM[Saҗ,ua5'Nu P@7ѿdZ)S=C:E^j7V`n/#./6[C2#uFin5#*qOjI<][Gxh夜&7'X^ K)QzT=\fE`IEԩJ8L4"ܫbdSS# 럲7~A|1ѬuMM}id^Vi]}isa#*]qr[ WzUWJ|6:5#USt2< ^3oT1Ik) F\|o$#$GxTixO[1*<2 WqNT\jjGu+i~ڼ/g "=_K,t[9!ͶucekڜWhw~GvD[]yV:;h{eTRu :9lsj5G^Y(۫Fy)b'^\r:2rKJW0n2p'a UJnC(Uߟf 7Hg:gƟ"V,-sCKBKviέ xsÖVu^Zq-֝g5AIc)3W^m}^69 U:8j r G+MC 3 ־ SoSj';9!e5EBgs*x9&jJUfU(Wx|EZ8ڸ/SgůxZV?c>*|@o4;PּYkzGR@յ]CJݧa[7Zjޥݕ:;<1l>ę R׭ VifXU_OK,28|K^Ɔ>*QQ.4<0_ex=\>Bq00(e ty},TeO-ӭ[N|VOߴ?j@ sෂl ?h 6Z(" JK{EfOb3Jk<xnDSά_e|r(b1*ixO .qP0؎3G .ZX%JTN1xYB2U9|btEޯ? v^բ5+-#MDNR--`}J3/w}mm'$,v25Jup„#:e8p:|E[U#IsBRe/1vk:ckNg*xUjU.YrγtFsUfZ<jσ/lj|"u]j>1N44^@t U.5et?G$u m-4vg40>]O3OW hxJ6͊E*^ϛVOeP8"ȡxj|׫%b1|mLOx(Rӥ:Τ9U5* +i/|i>*>ேeh'j@]KƖbԮyFu}rI㽦{VV8lT5Rx7AkW4|?xH F:Mzkh`y&TVDv_7­9^mvƤe]!I7Q'h ^||^$|;a} qE*?YJȳL?i(1XG [lL juZo;}]sF|;š4:5!o6Lm/k/.l$eKn KvdRwJtϑ&u ?U:iMqlάoZ'\0β** 2u`F}_pR:us<:J-B9.?r,S48ZX:j4 ":ymyЩI)RSq|q?b_]F|P}ZB<u :|a>{X W$:^>sCrNYwq} Wbketu0A5:V E9Ks84*5ٶO<$?|%s| nrzx;E&N.2;ę+VNoC/,~ӂ (<iGϋ?_ Z(lK:}Dv|$Ϩ_K ̩y0 V*#Y`'?xt֯ ז~ʜ(aMX¬a0שPc`0)e^)SUj~ҕ Ts V*J(\CEWlQC|+< t;?_ |'iEno-;C5RkY[j6뚖60ts*i^73ѫ[SUg sĬE1E)_8f' R5\>#uiI>TuqUXюbUi–+ 8ԏ۟> 6<#SCu_;ߎ|EokZmmxV:*_Piàh>Mͧ\Zr0}VobK8.2sLaYyF1^cĔإRL|'ӡ?kCXpq2Ld%8*u,`z[G֩bμg <O(>֣5$-f Ζ~]R; 6k%4Mou>!Jn4kC>u0b3jJ*XJSrhӄO.α>(yZ `s R+g6U%7 Wü:b18(aVq+¹ :kpaS5x^g^'+x,3115bȩpYcj<5,G <3CJ4Ŷڏ;fJ񽵯 &7z Y$k'$,'gmNyyL*kc.6MJig'9T^T(j?[ Rx-yN+Y8|>qTʨaSr*L>@RPQ TcR#%t5)Sz2xS·-j8aik´[ W3p7NaOliej%Z2KeJRQRgQ< 2gd<8?[(NpliIKSúatC,ʤ!?q+€ (jcwόU路tѼ#$[+km HpʶwWڦ4"8."?CJt#03Muy1 J,6g M(ah9c18jSs.]< )4*$_Nj^Ο(Qb=K [C>-|1/ﭝږńXhۡj=Y5i-84@Y.?9iG/\Q2,LT_Zxzqᄜ4!NeIa಼& %%Y*e{Ƥi  2LKRZjuք ʽx*~^~۟e'WNo[9ui]-/P֯mtgK/ XZ}[51N.WY~8\?{zE1SN/gVCV̜ xڹ:ʔKXҔAѫ.SyKn s[;̱/ N/9yF Qrj4d:t=K|-~=!mxİ[x[G|es]Gkm&iS!KkZ}:qy|/0p{F)PSU)U[^E ңkbTla^SՉW+%K3g[[F3#h,%GNe4a}f_/>='"t_h>mxCZhtq8XL;#׈92N 1xn ӄ/)ө\)aBQ^V:ʞa_ ʲsebp..'uiGimӥf/xSz~Q9nmCFjOψxQ*X5Y2M* Z9N?<'%|^: R~*EüӚuUpr:*n#_Fhd_7 |9u@Gu|)|Uyxn-Ch8< x\=k; R*5)`]l)ҕl4 #%RTV'P@P@( ( ( Gѿho><"w(w>8е]Y+ dl O*4J 8N*ЩN^gZdVxj*4tUFQPRjI*5+PhP:INb1RIʜk֌UfOO\׉?aĞ x?6Gx5 EPѼIZ? _/cKQ[514/1kѼT~ʪJwF$yҥ'yB8UN*+SZ5*uՌjRNqp:' R$(ŦGP@P/IϏIWo#/c fa<~@)Kd_>-oψaεюx3⩴IJ +85q a5pGV\ML:KQUC/jZIJ7|M#eYWgx< pXc'RJ ^{Ie떭U*6Wg|)xwH9Gºz~ iV:ILt-lmCmIg-줔aӣJ"N0*4iB6:TiF4RPN1E#qxV?Xn7Z#Wb՗5ZMyԭ^I7*jU'&96dx/x#_k3SA$~!ڵ{_Y=C7dI0\6 & C9Ԇ F 8NpJ1iFrQRiSmBFS% eG JU*J*r7EN\߀_2_|EK׆o|)%?Mrͮ.+뗽ӤIbMsi7W6W"{ /Nkg*~ ?ѩ˜ 8)TIJwUJU)®a:rL;2I =ak:t3L,)Ǝ* ㊣QeqXMuB^]x?oه &qOyh#ާg-H6km+TĠKqaoGeq2A$V7$scp|F"AV\j2U:%Rյ*Pⓩ>o5}e\k:5TXܵk`Ʈuƴ:RV:> x+ 7ܵGkM& A 5-RX"[[T ]OSX`.^8cThҥK Kp) ^TpM*qI{$Ir<>θ/Ys>+B~cX SCoY-RIj\\GkX=j-b *sXSpћCaRT*8BNtg*r9N)SɸJQ=,ˇ|&ǪnتZ(QVrQBS ΅hԣ)BO>;'~5MG^?w^ llu/X}⻽<rxXQҋZZ1RM<b@Sl ´08j8UieFaW.x}fq ntiN0((Lϊٖg0XD Ypu`){<*jUEUjRSxx#ǿ0xxSAG#~!mw@ܰmOO=XTaqu0*b3u0Xѧ"+QjSBqiEVl3++SaqJpج5zR[^գV*Sg +&>bw ? <_aχïxG{YM%|1ss<3\xNW5xrLx,n\X ( F LhXttjsףNqR4B5#^gFD}vuOq[Vqb]7O*T1iFaCجT(8:[ ேZs&WXU|?aYϩ]- K,"MaQaiah8|.(FsIƍ j4FU%*PT)IM3|;ż~u9ҥAsLn't({/VIJ^ʟ?%>ir~E.|WWKxMKjƉuj֓O$QiQM4q[M(o3dL񘜷 [UAV* Q!Iքڅ*P#Gp3#\/˕oSab[rx- &!Nn4\2am+|#?DH SGдKWk};NIe+ϻk%I׊P:PaJ8ѣJc TiCF- TNPGcs cqiY.j+V5#N3)ի(ӄ)rB6c/_/n]+_{7fv[9[ir G$z,n6~|GMWmCc8$12#:^­y^ҵYCהy}% ΚoiNJj*f8_ [/x3pGSJ}f28⡄abїiRvҽO>|-qsv>U =~i h:&7M1D:*{]%_6i>ziSB,= TzpCJ c)ʤ*4 tԝYB⏆4_W> hZZGMSšaw{FGw&gc)0G>Rn*qN'֥Ne(Ԅ%2jJIf8Ͱ8<.晎/ͩŽk8|gF7aU m:~ҧ%"XүB%N:u)PZ&qQWZ"ZkЩ kRգVէR-J))qjQSM4?>$|#' AwOx~ bֵ5S[\O)*,& ARiN[pJ"*c'ψW7)JRVroޱUO7,U)RXʜ T)E(ӣFSJjժ֫9uݥiua}mo{c{o51Z[\ʭʭ#V`baTj*Nz*uԄөNRե4sȣZ,E (סR֥9SF))ӫNZ*SSԣ(i3~| I>FO3k Dmsjkmu%ķW7sAggj$S U<5 XL&ҝ %BLElUHǙOZnRR߽c#x2oY/7̪RAⱕ9TRQF5J!OիUխVsj (>=*Wq Cj_ hޯO&^ͭ/j]Ou{hs\Ms,M+sO}aUNIS3P1j2RmK+˨qQ3*õM{ 6a5ҌiP*q~MHH_ǥi) 4D]!4kBtd"l-" b! \+8xԆ&BkBjsFjRHRSRσ^*ҭV"XקRp ЫFj%8ԌҒjJᇇ#yKI|1o h{ۛ}@gSGlO+%frM*TУKF(tPӣFRNJa9m9JL̳L9̳8g~ec(QXkTiӥOrSӄa T|JSyRpT)iJ򚄚e')FT\at"ίX/ j}KF3 NRjJʕ(Z3m)RzɸZUo~f8ҩPJ~8VR%V0Th˝EK'xA4M ⟁|=}7N7bkVBK&&OHYYe9*n9TYԹ: qjNNM N)J<Єj:ozUm)I)SgJQsjT'h5%9>|;BQS^ ؑ%ot"ưѼ5}v[kTI{Xo'kt)~Z ?; mJ4`))({GN 0u9-i%* E)GeO:ܷӏse(FR%(RZ&oƿ> |J >"!_j=2X<)RM{t5 sH+#m{V1$3ap81FRQR(B.mk&9]%J;p79prpp/;v,y^,o{#e;.?gVEqmso: MVHfEY"6W]0uVQ:UiNiU9SJ9)B9ũBpRԣ$ijSVU*ҫ SNc:u).3$8N-Qq[M4=꠰ ( AB=^OΔEIJ2N2qZM;i5'mVj|?I&\U?=qo pۘ貳]+jjI9/aȣgy=$9%Xe)ns&]dۭ(Jrn|KHtTKC,&ү[k&Kn4۽:),l.-]hdZkF8%]T=Ol^ysO\OW|gU/efO܊)ZD˧x>h q<3-'J5 xg˻i:*'Q9Jn4B87hSQU!nHFs,Ty/rW'v>|/Q(^(׾Y.۩gKjstZΓiFq55ڥԗW \d,ՍpiEFiƟJ*zpbڌ#ѶkZ ʴ98ʫoI7ԫ+USbfh^gEҼ;h:Zi:FeV~avVтDp[CIyTZnZ7ʜIMF*1\ъbQI+$! qTbSs9;sl߃ k|Iok$wx^J[Z>hۡeݮpqZYO%hn 4I|> Y0|,U燡NRSU8Aԧ(ѩ7(ҥ.^hBQ dX&6uY,"]܇]N 8غ4iRh6#N)1x(VU*RdTqMEz08Fa18U%ѭJIa+T*iTM洕| '[oD!Ǿ#{[{i~)lU4kkl$s;UgeujկW-T^q^xyU8RB3RTe:4hSiRMZN|~K)V22Bѫq(Z Sѫ*tUj*Pj jTNRe?{A4sCh֏}ii{杪iZX:vgnoX-9$Uz҆O0؊Ozz4kSzui҄ڼegnxO(5%qɲ(N JXTԣ$&i4W=RtgN>Vu[+7T+H/KNK[ 嶼[{[ $h7emСW KNtЯN֥5:uiTRRg Qvicc)EE-8.5MY )~fOϑ _Ǔϕ痝sr+JYnJ6Oi%VNM/ϮuywN?Un=S'rƟi6:Vcgize}6V})mgccglY[G0BHիVZTZjVYʥZjIΥJ$ܧRrnSm| B KaBңBq:4hӌiҥN18F0TRQYP/7h|[h(޳lzLJEXz&ḫֺsa}l̈YTʩ18\6201tTt14iעaSPՌF*UIʝjtBӄe!RZ5#kaҜT)N"XJF ZԡVNe 8eo'?L9vwpǷ<ۏޮgN<,t|qiѤ֚=th?nWr.K[#/n_t=Q  x4uxoF> F!Msft?tV%>%Db_PB#=zPB0{/B4FTpj>Ɨ9 NJ|44pi`F18w#ABXW:ѫQTJo+' ߇^i.#GecuxJ]=`C*FKc)ӥҥU*XTӤK¤g{ Q*<^ʜcZ)")} X ,TQ]O BR7R)a#Ma:%)ԃ9Qr~~_k//FSB.c͖!_߄z//χ:?ídݝ_:_3+U7P:m4ȴ+z ]>&^\.# K_ `QW ESK8:41Ӟ6*..RīVnrpyNUX<Ypn\ b iS_8C _~ ЩJ*c+st%WwŸLpd=W >.t?~OíK#м#rAok&s~{-mmmXᠶ1/u*tQ!GMTRiѧ*:9c'g+3eY^W2] ҌCa#Vq\EITcSMv (<]G yUς Ue%aF{(u0>c[a(Tў3 JT0AףFR%*TFU7ˆ9&scᧆ|ghI,:.[MkVy4skvS&PKId&I wY`U{u\jPRQN!%sa^sN<Ƭ-IUʽ8ʮ'RҪP J2t |/+/π<!xwOg|Kjzށ#yOזז6EskuoͼM:rp<Ƈձ!hPЩZgk7)+У0pqjEJhb)JjrM='Nr\҃(FQ xk^|Ɨg&L,!X-m RcF%y&K4J)9rօ:Ta0:4)4B*4i•*PJev )5<& FjRMܥ)ԜTܧ:)JRT@P)?>'>!x7ž<sx{~PyA{ݛЍݩ(.JJх:q)6!)( !a0,-7'O K Brs0N.s'iIݶ⺯.'ƚkTMjwß \^o)+.NL_]$RMWoO7eXJp4*Өӝ,-:UTZ\UM{Hԧ5Vmf7xw1Ȳf.bq9~zۛRtIҟwI#4D8c5T4Pj*UU@UU`` rnRnRnRnmն=0aTc1VcdIY-8>$[ᯁ; 4~(N.70.ZZC}t/m6fн02xLzX5 |?u5 k'MZMi[Ot-&Ům-ni=2ӇC N,%XZXҫ Ԡ*5+BaJs5^55r<+*}\e<>+%Ju(}bV5%)䔨Rm7J xSa|@ִgVmciV`5?d YVWWF--BF{ (a^)üuHVƺE*T5T'UQV: x,$*xwa,=coᡋtpIIэOguwkg_:jVo^~Ye{?P瓥FuntdGt=~FMTb04*VJNW b)xAEF*5y,*YRXZalF3rs WNJtœܛdg|hӌ3 -l? CPBnJeR5*Nr[77\>^ŬkZ}xTGY#4\60f]N פաB*$gBqIÕi&Wn⧍pM[Vq2NnՓZө'RugyΣS=WZZvW:nj6ږiב<v{֗WP;sks Or̭шtgУVʥ E(WQ)):U;J*K;J)[IG(:p$p%(N.$M|3? 5O? |S.{H-͵icݍsE$Uj0,&XjWV>άR9ԧ{:#9'8VR8g08c0YQSa%,)ӣMӺmG ( ( ( ( ( ( ( ($$LW?'JX$m$´ PXq. ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( ogտ %uM񯅬W-FHћL[83, 9a&Kbb*Wu,VBsb18,$ Oe*,=A)ֆOcq9){LE U;/ʲ403 XoaCb;l)ogu/?>=Ꮚ=| '? &j>?>0k~/OӮ'[E<)Y# y,%j|BY+/kcaUؼF]o-u K[o,o&f IaIb GFVRAJ hV:Uԝ*EtӓJs(-]4ӵ8|E^+ R54*XUZJXf6 ( ~%9>*| eL8??gV4o x]W }#?kڭ4m}GT.]C2[Os3b#,0eY~;4eLF78Q:\`)ϒW4h/c3\~+O̱l JΦ# >;V qKJjʿ?r'?¯|.'/>.=?=<3/~$?cŎ-+iV"p2+>+Vh`2/K xv_V|&:xg.oemwyyiuFwe}wsO,.q 0u#fx `3\ Xw(JIƽ)=hxGx7%c++9FK7STNo#R 7T1Sa~`/sōo'ď?0⿄^ݾ4|EJKya |1V? iu_6Z΁oix?ʰ\C0X,8a:l v'K01518Xx:]BxV?dβ+(l>)e9fu1ᜣ#PeWS%1kG9<26"jx|dc~̿7]WC| cg|=~x7¯_\izwš֥ۍ+zoשȺuېfXҎuCxs2psb!8YJUL[[Ыe %^/ $n2 nc_8f8Zvr͸{<冎?,pp<~,VWVx$J5Լߴ]%/߂g?%XgYǁ=sOxfA^jyz.`x;'̳~(y~' xLY^K^XXX4kc1aգF1lfBPQ6놸SXL׉82Qܻ9d<#39`佅QRg[+7j~ <3|Ec3ZV |fkzs'5}O\~+'H++-oPog[xiu-{m<)(q FTⲪ¼kR<~[ ~Y8+[C/2\_0EWUb> 2O51JXXcxX<:ҭy Д1tl\(Pj)xW3?f#19g ^Wk+/γ֔2Zxl>7XlcC}bF E&~?Z/ωx/I:7Yi湍iuxT9חW!J(PR'Zt(QNjΔ!&} Px7aϊ? 韵WJ}GűjBc^ lPxgq.4KcQ|!gij\\}# :8|su]|4J7~_,xXfK 4'Wq'+3p8fmJ8L~yu0rp:9\e1K(qTRh3Օ5(:xߴ++~-);|l7>38<5e,W:U]wjOef HpltpSpuaX1 u95OoJ2 dxCYgpFyӭK3|OQLi p_Yf*kkZExs᷌5?q5ͷu6\Ksu{vKH^m25MMCV}{{$*x\M<Zoxq0ox .;.&6zӇلp0pcf-l*rѯ˥Nxn#qӇx9axƷG_~|K_/x]n>"Ng%}?^%>WΫqi4ຯ@Դԃ+Uaex;Je|ohw)hֶ:zuK s<9s\&a{ Fwbpue<=\UpVxJyZ0\d< Os;b9q7ieXGc:ng6QB2 bgՍWF o77=[~ ~GG+!/3_m=O+NMoÚ^ɩkyh֢i幾6xh>x#VG8|#]*USJE4+DgYu=ZLlOR̞6;.X2 7*8l.1X''4g¥ziTr ~O*vw[F .GJoɍ8NgS fTC|#^GQC8qUqRM'y?}s/F2!/9j_k wOwK9x6ƭ7$XȰ~.5+I;P%hMB >8%̸_8ʰG,^C< JA׆#qp*x%[C UqXƝJSRSc)?o5k~>]4o"*yOP_7ra)J?G MF))9UI$oD>j.ν!>|NҼG/V𷈼I&꺾r6dZu8V3sdnL*p<9x4Q:hҭR*PJ8#*Tҭ)ӧ*0x'K:̨.$0ax*8FJ2`q[Wԥ8FL~bÖTR_U~Fso5ůjZSN.Ko9h3_x_xqꭥꚅpmgs.SI=/jK +D(neumld4{mS[[=.gGgˇتT'0rk*Rp~aV>,:ju:s8y_r %N:sI*0iaVxu|.Մ| @|Md?dk>67%Ewqhng5 IkxH!mg7zϪ:#~*F7% tz3NFSk4As9r/ dgpA2Ы^*~&?R|DVJV#=cNѧJ)S5{!@PGڋwŏ[e;>o~OYs಺|MñaCgXա¼Maҥ*5OEC_p<3U21\Ub0!YVce`':yypن* JrOҶW9Uxl5UQ|p!`x3Au?I=C?<+wּCk|yۍ{M[~e<;m%׉<=Ikgy 19F+O&sƎ"xVGy~cxU\4X u)W9g<Ùχ5J!f2.|*eƺ9WQ`+Vbxia8*ԭeӝSc?m>~ Mğ?Yi>{ᓯx[žuM[R/u]7W> M94CWo,k}5L6+u N>gN NqXc  oZUVQC x?ǃ3 G62 -n$d?[sl<- oCF^]SZ[)a%G N.%/|Jg 蚯=F/už*];|3F~"ݗ6n_]-77DvwW1y#6'-VȲX0eWIӡ\\NurPVӗY_G.#>$qn2]sƳC{LnaFPSBN.Scm?h(s _x_/sJe.o bs)q~b L2/ e,. =5Gp A<::u' M4it4֍5_P0 #*|ƶGtl0xZ #ZM5:U:/ke0eeN&R/ʪ^:fҝnZB\N*)VO CRZ0//)UcZڑSahJEV -֢xG xrS}OyO|Ӽ_?$]MzS>.z#մ ijqPX Mf6z%㳜g JUR*УN*[,Z,>A}K5֧/xpD8{gYs89ª<aex6mի֋2Ow~?'-왬x'w cپ%,?xo/l. ͖BOmCQ|18ldYT#2#E P<?eױp_?i?ŝ 'Rkl<#}K_jp]SiYh_K+&([SI¹~cq*iӝ.xheتXBTJp̖uq*S8VXl//G9<#~uq3:e|DB>d/0)ӮINK+? (?.wY|U?e}o :d?>.q4Y}ʾ8~.XV_!Wsᧄ/kn㿊^7tO 7:~kZvieA4:boƲ08qef#⡉8K i5U)"Q)S)UR?/!x|7fU`,^YʘV_eYLYja>Aׯ, CF6j~R{g>wdς4e_2i&u;h-.g~^o]jVv\u +eXl$b/z2Xx\q>/Nu)Fo]pΰ+,2 q%xl>BTJbB*V^)0jTc*Ka)Vf~g[C"iO~!jouφ 9. Ju=s^i1i:NϩGs$v_bGreh!٦|QOx5km9N~<v:4,~?r\X*> 9.|%ZY-lN*%*U7J40ԡi]|B:4ϻ<5 an^ 1Y,Ҟy\=Jb1 FeMqC (OGo?xot|G}K YxkQ:KkPRW֮VwccAo|gx_a3\}&ӧVy"ZЌ壇QR#~ _?f o"V[g9H|Mq|5kWm_hڄ3ϧkZڏ-KEK-nHazSCaq\.; VPTS REJעTR7e|ApoN4,[PrtZt1Xw8ө,&; :ңRBJ4'omw◅/ |7 6:ZTNԭotNxSyeyoc'0qn;0duje \V;&RNi3P5iէV3܄-r3|00jЩcsC?བ&oy "MkU 3Pv[Ə{i_egH;M;JI;}2Hb ˆ\ɋvj۝y蜜w?mEiՔxŴN4cpr2P. stFSiyU~q~֟7??ioi: kMvEJP?~4ֱO xD}KTMLi:Eù'>x _Zpҫ7K2ƪBuiRq*ê5pk/<| >;Njr2x,>W0*Z^IbPeoڍ?5yj9[}>gĿ|3Cwtu#Vռ?mKľ|)kG [ZT:>la]^#e9MZ86]S7PN9 5|^P`0y֡S<;x_<7C 0Yv}C(WC/qYmRjaa1Ll)UVW3ag~'xQ<=|R/wխ|;;/zNeI[?kǪ+-?X+[75X,0xT41T(sԫ6YmZ_.k,+Q< 1T!xYWj%̧`19YUG_<}\v.-_)~6im?\{(n-Xk6L {-T1a5V+ TrŹR֍*cFd0%UJ#.h5\ΖHF3 \*0뱖OWStpQ\@P^./=>([8x~cZe[%y*\$El4q>U'V2tQ¤H4 ՚;s t9iFurBlG:Rru%!H NSqM2#y>|L~*| |5Ѽ/Da~e_^ TV-+}/L`E %ֲ_)S9>U\.q*ptӃs LR*Up4kOIƅ)'G҅)҆')U'RN i\dIJNU\׃8~8̽nPӴ]_PtCXnmwcwֲg[s[iSW Wz6L] #UNrM֜UIJ0sʥ6yQ*VNXЧ:JF%+JMJM{4)+E94M,k࿋>%CPn-?QfZ敦jPþo-ZMNR _kӛLl^ Nod؜F1\,爚85*pBS_sfrʰT~ZײXӣhEcR9M)Bg/kǿxҼ ѦڸW.Gve}[Z,viprB\xLԢUSVVNs囅PSaRqҫ*tMF&OeJWRN0Z%*qiF)J(կ*TXsK ; K?o? z$1KzŘ*QR:^7qv\_KAgmiz'ndHm>PhKy$m6kxjta*l]9N=Zi:eR2WeK*C J؈3w[[q«ZU|Я*cG_J; (͏g߇|Wyž F?!VF t= ᖉ{'uMO[6|9io%VdeqGg9vUieўa XMjXʵbTka/N BL]~|,҅l / ,mxwGby |X:ugx*Fb#S w_k_>|߉$>4YZ[Lj|)ڜ֪̖=̰XFѳL=<&eah*Xlf&5'.JUeVWvZkc3,Vs¼;c\%̲\8*puXJUi7htIY\_<-w}O/z>|%< |hTc#=YS+ץF*8l~7-M~>%xoIsB k>3$Ŷ%|Eg tcmcˋgةF|?if nl5 ֽ:R VY(WFx)8 Jtk}W bx.xOb9~U_O[-:L\맆Y+Ҏ*oN8)8:P@kWŞ=oVqS7ԭDŽKSGg47O.>=CNҖhm_k-2;êRJWNX>h{*zҬIԄ(֭V3TǛZ_17KB\KjTV᩺T:V)Jr*pUo9M|)_x ;}/~>$HԵ>fKOI.g:֚VF"-f[kx>(b\0M҃N[X.g)׌5*qMR C2~'gf\3`0] a%%WULm 3'MaYFtL=~?Ό8# |/G"xSF4=C:*Nmo&̷7smVp+\^K|V&Noehpת 4&&~jxou/ڗkA狼Ws|/[g|%a^nxx:Ne$BѴ(95贽{_s o=[SB0Y,-ji`WiT"# O WbFXX:x8ʖ37ʩLJnʘg|Abi㰘<=9Ta׫R#~>~a+_ei|7hWzhQ2OvN,EKuzl{}ySq/aV_1熩ћZ3veAp|Ӟ]TI<ĸ*fX40غxV Jxzø_yj*UW?F/)rҥ qr,bܞv{\9f=cSnM5aSЭZjaja7bJ=-pP@P@P( ( ( _w?a%|2׿iA e{}OJ_,!O^3-ީ\^Cadv?27Ga+S~gGaSl_)F* :ʤ|/ȳfWmrF+c#VUWN,BJ y%MC#awf"d|]}hۗbw]_ž|M(?OxIu Jhzb^Ϭkqls}:Fx\{f7,qKS\Ѝ,6. ~bpTx[Nq^7S(V#UA5SVU(&QRM\,/\G`m9ʖ:ڲsqVkvP@q?ğ>2&?fOP}|UnGi~ xKdyT44[ۆh[;(3$<$՝̥k|M¿T*wԚ̥h3_0T5O=׵QJ Ul_4>/ y S'±sYUdM^O _UZ 1 jƞGUWQZ复tC(OJ!Fa bb-_nffcfQsnG0o0PD&C2!]:MN3Q#h5mtrL +W.rWsJJyPb+ғj~~ݟ!@P7=^S>]C~κn ex͉WU%D_IC#rgg7%Vm=6ە%fwvCGudjZ})>K8^ʤ-?} NM%N0|1ECso+[Ӿ X&y#9GDWVOYA]\aVxFZ} 5jS哅Ffڄ҄nY]#o=*uό֧ j:ZU"N9? p(%z6~2HWw6f<Xz_qkՌbETKwV#r&ܞmtoos+P𗅵owźtMC>Zt;oÖ$6&,/{A[XëCg41Z--F5e^1Q<5LZq\]\4 *Ou*4J>1X,N]O_a1x+TCKRTԄBTiJ U?sUo=k_ϟկu}/)>K<Ѫcfmk-o$MzRO*oqqVj|!p:%:U8Sn V# *ةb'!U0xJxaf>|2쯦.}O<ak(őcX<=`ōpP w~Դ/ŗ&jVW/XHTKq `Ui#,,,;1[e(Td#C kchzG 4x2&<-dհ|oR (ԍLV{VJ8C:Lw=v ֥4~"|1 SFF,R|d;KO X>ռ5c͡/]Cº5{(.hڗy\4^#?qT0U)aVkVagSJ.?B'B5Co.S#,<8LE ,3:(ʲCPXXcK."/^CN,] U ]F,MН,E*эju8Ufc  7馺| Jm%#־)x#J^GSawqO)XeuG&:KIQm|ڌ>4zJ8X+{Jj5$)lO7 F#TxqԪP.U/ Մr:/4}{ &)' ;jɎ8w,?>#N7^XO"Iia{LlI$(vR(#BIKs.iӣĵRk:R`pѯ;&G {ڟ2usGBoU|9pQ$R4r^_)b1]zk9 3[\ŽRA<ƒ<2Ia' E"3$:1V+QWN QB#Rj5`RZsN)Ԅ IQN:)TZS:SJu 8N6' %(.j~ڿcZ[li}/>Ξ;Mxh> Ҵcmyǣ$PYh![~k6(2Yѡ6ipKRC/xF壈 9v.8Z0p.ץ*UMˆ(q'SC/⯉;xĚ S]շy/u4X6fOWaX2,+,.^Ub1SU_4>/y S'±sxY>ڧ%Cx{'HVRhvel~ܿo:?Ě71=ڢYVCQ1exgwP4MsRew7j۹k7ʳ,DŽN:aJ 8:὜#[}w 2&LNGS'*sI_SʧqexLv^1Wޝ<'NgSeY+s?<#wnk>mG&Xiz ak $4Y.XIr:Trߕ9&{]{KhQ5PkQR,[ŜiT'E%j t7(c+JN rtcV*wK~1$$OßI9$$yw$iI-]z}|^,I$ IhY2.#}up~:yI[ ՠhP1iQ6[8U/?%j)?7]cXۢ4u?~TB?oVONYƞeJ}}V-Wv~z&]W爴;]_扫[:N궲zV5YO=R[M,3F%}#CBF#:UUjRJygN%xjQj>N ˱L/b08&3Va1xZaҔ*PUVRHFpeυ?oO; &d_Ο-šNJH>(IUSL&/.]i;mg.<7qV?0^ka0] FhS2z3LPl=jjKN69n:7Ž:$Sœ f_Xe9SkJ,dlYS|a(c)ѩ D?L|%ٻ'(\ 3MH%_,1Jjӗ}qv}g3_O NqJ0~Zx5: :)hP:j)T3z/SD |<_Hm_E O/%,7O5v`ӯ|CuB?ϋ1jSpg`gº5c]\½1e:8:xn QWb>l˃|6º2ϳ>+ |e79ʎ*i |xH=\s_xsX?[? (?_ utYe-4?497L ]>m" _&E5~gM6ܱ}ĞKo> 'Ycm-W/U4#Sx}a%NҕHV}S&Z|xn Nc)Fu3* Sq_ Gҝ-~[<&ssZY}oK=U˾<3O 캹&Lj۽^6_v=Ooq HU_Aat U 82)8PI΍XV7NV WHBq;b]1J`bpjѯIƥ)Ǥ՟@5x~A9&Ɵ- _~}Otw ]4ROŤ]+os$Xϱ+:8/ 8j`.&sl΅92o Zp]y(b|2T3%xn1i?L3qFP .&l^?r;@g6IҼ&Nyg+OXZױSP/o5KZwsܴ3k_*8xFa(Qʫp3ӝJ Vԫ)Kì~7f<߉153l6,3̱8f&&"jRqQCp԰T .J J*QG6#~:柳/4MS&%ߏ5ω)>}G7]3ċ'mNc]/~oj.nG6p#u8W"ah̒ɲa)R̳ b19\nxꘌ2;NYa0f#R\Uzo3VaLS$Dw, #p|^W[B%0l2Xg̣A` تS ix3㶑sx# [<m6Y4?xrTo<:l,f$ӡחA}^ϩ6OS,&acY`:xLglԗ:'-Ƭ9aW/6p&/~cq%*q\4%Ҝ(fX V9$ካ*kcqP@?E}Z]6ohm7UY.mj Z)$1N闉O𞤫mרkmVG: TrJN\ӓ7)6lPaxG:uix.ZJ*ihjU.HJ4)G߷}ŗ =k4No]FؐJ]Y\ڸ#'qg0x=x( pp<#W*G+j/e:XNjWJpqZ$~WG|3Y񕶅Yx\Ҵ}_4:}Ϋnm^Bӵ]Ub[?D^mx,UL[ XW& bs O-:>h{(W>5*ǖ.0V:p<'_ :jP^PmLk>(ʻQ继/8-?lnگ~x?c:y6M-,>!^ѡ7, ..C¦y샳|*|kqd1t2<֍<9e`JճLvcc]b08%<4c6)R4q7ӥh3-#ԏ4- ˰ѪgcN(|kuyl6L6{AKw/X/˫)b(uK4dw|ͪ|">xD>xO 🍾>4|{T^6F)s3Ow]hko\AGzNx\?F<9NAGP͓z\E,d\-8B Uzr]~P@p&woOiѢE=rJh#\\GKjw?IJpU(ÖUhJOMpUIMtO[;C[S/ xCό;x÷i=cIu+McJO{Y'u{ RggYZ[wE"zTqNxlN^ ^ &մAhFoztōcETM+Ğ#c߆+9[_KmN/\<,*3$+dժQBfTTѕZtN œ'V(xŌGZX;rk2ZPtu+R3 %,FMTtcZ%(|by2^mƁX$N S scPk[䙧SV!.J cxEOУGܪ0i(ҡ+ O N1O q8'Wџx˜l~/Y'^I1 'ͳXڳI/l<5,g^)&1lOTT\Cϳ6\E p)2c.XZ_ :8&}5/~|#/n|`aOsZi%o/,VF.nUvlp_p2Nx\f Ip uZ N1ĸҡN7VB)O VpV?D?( (>>h_.a^FwG?_)ϿEd_Lko_,M>S&tc\Wyuyyů%_?xQJ wbPA#ܗwQ>Iɕ3]cr_Ul|_֏2c{ό1`>jZ6A(<+>X&_CS\Cq^9> BJЅ9FGJPZJ8XeU(1^7.' =<2ҧhcC*?;@x#/83 Mzׅ/?? Uisi.7 O\m趚X] +xlENPc)*XʔUlNSk9pG߽ok X_iJƮ3ZGNuC/$Qe\??ҏ ~G<xSUo}3R4٭SlT") f uԨUUJ.'NZtN IIZm(FJrU(I&N$vwRZ|?G]M'V_d&7 _WuDʴw3:0jrk~ 2;Eb1+O]gV朹}5:ڍ< N>j iA9N8,*NIN*XL-Jʾ2 pL .-,/_2εgNJkԡ$g5_}OY&7}%O$o.7˦injQaֶOVVk uOJ1 >-8TxGNqG븇JJxz*У):sWyc"\dKג}|*{5&nxwu[WOx=4-fI5sIcDĖ:Ūo8fx|d_xIqF.aSF>$1*\+գYQdT㇄^i3s k*]j[,+l. u]*]R:5k֧VlD.hߌi|_ h8YGP|# T]4 :.w&a*[Zuċ Ifxq35صjPby3. e:y^.VTQ=8+>e _,0l(0h9՞_G ⲹUSV ZN&sewmˠ|-t=.~zѼqO^:.SWWxN[sNyt+]b+ M[É/+z+oA1n[я7F`ן'8;θg[?5\^Ep*xxWZֱW Ž]Nߪ'@P@o 1_ U^ȿ컭>?+'ˊGGU};M+l4Oh]ۮtU]0ib FWޟVqɪu~79ZpNuUiRlό"x}Ų7,WJS7*GӬ85htjE*ե+Fl߶~Ȟ G({e[?|'i&/x[n&xŚޫ>,Ьtmj][u/e~ ɨfJkc[ͳ^x*T&)^5%*KcqX_X|%Jx|\UpvA<,x7JoχcC1U|FtKKAw2xm_B X;yuw5͵tzlsba y>MKc3ju,pџМh׍9ep*RCW`xA \CrG F"X2RUPεifObB#]#-ߋ45!k N,V~ .<K 6b[eG b)c,W3 Ε:paN#Д*VOF#[Jc^.? Yw\Y:>/r.:.;6 R`2W w><~Ϟ7auOxCI>w$n>( ( (( ( ( e.fZtڧl HU#]w>k^Ŀn[_ UxuCM|GME'čG,Oɧ+Yz;Z<~!O2UniRe>7=ʰt+gS(L=:a7K,.b9?L;3G'3\Fgb09n?Jq0x:8s J**Z~+ƙntolm"1ofpS~Q'<5?czESTeRN>iJR$c)JNrm. qP፪aYFUQNT>XB5(( ($$LW7Q10Zxz?Kh/_]as3ᗍc1Aaf}?ƂtP|ȢhʰbWUθw5˰utԧFiK7;f\ W_S\>K幆.5V ,e\֊W ғ~ic S)A:ў;o C//֞zNjt6ƣxK7>}R;袒̱4u r+Wch`1NOʳl)dT)e0SCR3 )RR|vOx8lpQqgqsnr,+0ׅl ha#b*8Ft1[8by.,??mۻV/~ҟ:ޗ |=xM:yx6?P- Y/Xpq&'V5|//UFW,rB̩a*McpX4>?nۿAx¯K)MɩO]jvzv^y:/Yͦ±>&hMn'^ 8*ج9OƝS4c%J.Ti/:> qǺ^įGL=^ {W-oSPVĺrxcRt<;`x{ pnew6^qᣘ帼-a3 Τ"K[[0t⨮EW Q{5`s_0 \EC8NlQx_q]c0X?kb3Le<5jjxcVss8υ0韶R7-; |Ax+,[&fqzF4gtCUqwrf9A'GҩKi,2NX9ca<%4(qWq#*S% ~Nupn+(aؘFp֯? (>|7|k&\g:?HџwQ->mqg`KZVK j ^1W+}SRYb'J]G2C!_՝5BJ<9R?iO0Mac`?rox~dsωp;B4gWG OR`pt5C>k6~+mQ/=:SӼSϧi}K-Hm%qE8Sڋ3e؟eby}Lf&'M`U_t~_t>-_\*'o((:u+xW[tmηc;?tx2jT厕NJXW_ʲY2Ūؘ4˓ |)^ \W+ [Z?#yl"3X 3``*8.p+Wj1Tiʣ#M#z[-Z?(Vn)s5s4+F6-ݬ~Wlji oR1_\jwmωu n7a}Mq+E+] W./c#9uuIU磜VZ˛^kK.),g 6EN NM:XL>kZ4+:n 6!jp %>_A?[GiNH~j<= :dWwK]X\fϥÿ_ՕF+K&qAʱ9Iar,ڽjU+\ۘlDrny:V.hF*jq/(xn0+pm啱T0xe8LUgJ1t:(刦 x_ 9xntWj)&4r4TY-$[֎&}P\j-2ll;YV.Wʤ)T|,НJTN*|qgt% 9\3ӕc [Z;KF ̅.y;+gX|08Xʦ*fzPpSW*0u1q OEέX~W[qr08 jB,1b2ʴ)$R7VpQSqqGgo/~J3s?^ϱxWA$jO4HjV ǩb_s7OsW8,gxWjro{:?\Uub}.6gs+xyÊ?.7 /ԥK브}b0Z*/maßSn?%/|!:i3YIMf%$[lJQ*9c|]jK)ȱ9(7ȪS1ZTiC0FUtT9~/seψp7$R$҂s4Iƭ4攪g~ZEJxW~Vw>earl4[;Fmn-eI%CΒ) _a8ܟ5{,^/-aT=&*9ְ(˙k]l>?z5lEMVJ'Vӄ8NM6ů%ǯ1'||?g׊|t<+gZ<'%QkzwO ~TmtmGP+_B CPw?#Y6l&E_%#9&?G ʱ8YUVcgVyZ= S1"W'#\Qp1^ex܏6,&. V<̨ٚa|OT~_k'||sׅ|YOWM63lN.2JK23~6A,.?kRW:}o쬻N!qf,,OC( !b_+~<\ >x;C-7ES]xgźci'-Siba]2ipqONĸ'dMYSa%˥Z'|8EOK/FLFkEUb|M>W3 3S#4dXft[J|\h K խMNX_kW<'~~߱o>> jV%<5Z׋4Kk ѼA&ķz D>N 9Φ]t9?19a0-Upj/0|XI8 <%3;./&- pvQ<g\>?7X M(V] _eF<Zsˡ`A oOEGtc*@ ֖?VԮQ}閿i<$^^"t'5b*kPY0wb1~eT߷VX޿,OsC.l>}L]jֶeXgP_ dC^2?IoG7kRn]t˫-9v?ge?.]|Kї%l%qg.J\ zeM;$'{9F[&s m4XU* )T█RIj_şWj.ʆ&Ib*0a(a ֬yv"J18Є0\3%f80?՜XO <2j% u8 T,1^j 5\?+W2~џOjo^is?[ MBb]Em7ĺڥ5+ > p^jj^,*dxk09[J+V8,V3O8+TjgkV_K\/ˋߏs¹F3F<1s>)5l/r.b`%[xiJG : &/Gx?Z|^xWk{;F|H%5iZSW&7˶H4!ᅏ&TpRr(IR5ow!V EJ5ԝl>J dFZR(RVI(R3" ()~?τ 764]+ĞӖX}_Mk{e z4 WCM2|GF#7Jܷ )Ս/iƝ:jS_3xj[ӌ<ܿK6e./-q >\.4CQ2V1>*/eo(؇#⇄>xo#_^$l4zo>1ZKoKü=a)d(pa3]hK,x昅牂 W4xF]l^upu`oo+-SNx_j%+?ںeإƟٸ_Kj+⾬%;.NX{ES_X!zu/̼OO__>{\.8ԏpx/>~uKUzY0Ax ^gwm-nI5{s5*;V%n`/:Uu9p%ahiOS8-Bu Atd~:׊ڌ#6✫(JPcxJ(Tjƍ^!ǹSrTq} ý_-Z?  kGEF[kȭ/h[K$D,9UNWuC5=ҧZiМd B14\kaU+)9py* ,-lnM88chʾXY'VjQXƬ9jBQJ-8o/o u?ߵπZ%C}#ėZioh7WZt_wH㳽Ojx|G*gy74rYEAazNή",c]CrՅ'9<ʏP̟2 ÞʶY 6؜e\TXu% V>Z5)x]B<#e'EO&/>2EθxAVKu XnbY֭)a`Pk2|_S^O'lDpiR\/|hTBjШjNs>8kW ?Yj|? pYoԅiG0,.Y~uP( s}; J??mM#L¿~&};2xIWO5_- WXWq۬xR8ivpg^8,FsR\F0X*Z ap=Sgҫ{h9SO^qo.[U.lN3jq_Y'XlUifzNl=~f[ùv*\637ai{JU%)MDioaoJ)3,Zz!7cO2ۥE*T]'( [yZ־#r+n+xIԔ3IJ|7bۋmu^r~_|.U_5_ [;;i66ri7V Ӵyƕu6k$ko~vo8W;e#㣏cJt99KvrŭZu6]GUhTP6>1u<.xb3< SZGG5 abU:I7QЧ' ~Ώuy/uMъ y|1ⱹ& .,gs1~; aZ^;:YNJƟ-ͰXlx?+%*bq}hSf2, Wץ1?g|Ri =KU/hk?4}7P]=D|$G^;+ʳ7FO gkǒJj)K~RV# t$&Q?/*' c.c,?}^}[C"X{IX Oſ^S’^Ѿ妙z%j:ρ~1ڥϨ]>]]40m9("MI\9K ܩaWRpUG<=j'RvTcKIZʵ+0\E LЄr)Z)Nʞ'??j/g '|9Qs?|?hiY$ӧ% 8lyA]8q8I&AN_R^OF8M-B9?\8ؼDr,,*ᔜ* J# ̚ibhBңKS oI|,fs\i߀?f/~i^Iա>1x<~}~]6;4eO[ R&7[eqO(Q8*nN֨ٯ? ([V ~~ =ZGO~^)'gK_viU|5ktsX>CC}x'[|cW@G?.uxC'G2jdK{hFܜuÑsǙaWeᬷfjY ThJRUQ,ΤЧ* .*`g=G gec?*!:YUyn#+,3U ?Uɱt8ת3J_Q̞CŸؓ߉s7xTX6U_'XmZV?#{z!Ϻ78㸻1_E%%y|ɀaV˰^?Wczo s, 6Q{ *cR)M%eᜏ)%y/g9ROޣ*sj2"?/)R#aaE|~ |u+]6߅ψgߥx&O^iRftWo>o)xgS|M3L2ŨRp^K<.ө%K x¿*T:at7<}e<湗G˩Ʈoy:LԯLLu[ J&5hpSKt|)|_x7 υڞ9xJ-kJ!“7vtK5;Y.;izsgK q? dUG1mJ9>Gxؙc1|ʇ"402Uq,$e 6/^|Wxcl^gTj`_gUhԎKdY^>eV,u SC0aէ ~[ Ҵ0J+FLN#q''z՚RT9-&VE;-:t?hӥJ*t Kbޭ_Wש5AP@~Jfg|x ~hw(/|-E5֥-Hum$z~<@--FDn'n1'n.6 g| O-U.˲mZT*C xMDљo⬧0dr gCRPKVZ8,F +μF.j [|OJYs4{O>(\|LGy'ҼAî4=:6mn&g|ux̛O9Ĵ+5<"ȳ ,| b،AC)ȱ\c.< غ8/%C~~$`*-tqb*ʕ)Y-<62M{8L˂0)-c b뺱j0t2Δg' W$wS v U?.їL=Ӡֿଟ_५Z&v[co!no1T"a7*2\kxg3\]83+<6~[ +7N52KN)\yM]Ԏ,)<ыUbSTԢY~+抩>XJJ-n:l?c-/W~,6)g?_o-<1;HoUմ+VQx=W@t[ JU|>{=VrYfc<[<$ʲ~Y^oC1.Y[ ھb%kSb%GpOQˊs g!0py⡜FmURX\ (<5ZrWl<]o:'_`ῆ|Ijlu|gĖ^&lvl6 B*ңVzc)W](҄:|KfYpQf9i0sljhc009)dx9tHk`kJ./*( ~|;_}[zl!:÷ЧT옦/zur?$'5X1B}lKGQexR*|U3 v_x9|)^]gMD|;_xgGt ş|Z|3Oo^/tWN,oeP;nB/eپ]Lm\8P\a ՇT)TbzG.c`f':RV1I%yTե?gs8m#%{J z4W/{g[j7ݬ|c{is,RXWbN!M *0n&5ക'Kcg̥kj+WpMԌ'fq SXY&jƮ_)ۖAB|U)B|D?/MC |~L>C 5$o6I(Ӵ=vOr9S=+TC늦a:uKK:\`FPV]Sc8S,57Qeo ju1<bU(ŧGcpbQ}Q~H˿?w-Ce 5#:A6otTúdESѴP""Ĕ/g)ќTN4:,8sb12 ,.9X>jbyУKUtaNNjiaNSc_ֳ(( } |) xKF6CT׵G;#vBf9i/mmc~d%sZt8J.OeM;9'Sh9kehv.S.\I[ D_D~|'?g aC|eվ#io1|-o^i~ mkMU ղLOk :[_Am^}5yb]4C`'KϩҩxjuUe'njk8WGJs9{LVQ:KC 8{ʝZ|ׂ$~XTek~>? gК{'CѼ+G+oizƙ~/屽};HUW)4ۧx.c="^8x/fVoc5VV|S(BbeJ9_NbӥZ*bp2 .-(+R勽27_?~xC㾧뿇o<=xPu{~}]hچ4[~m-EF_-zJT)VAѧVk4b0q#Q^|5wtܬlcQZxʸ*T.kRa&J*2^z\W(da|?kcCozO4M\hKe7o6rg2TղVzFX8>]T\ $UwjRԪ:g_ Gs 40ÕVߺUڢIxOߵGo'gW7Džnu 5F-V-Fa+Q%nmtXM/ 1'Fn=L_栱SIԴ5,=gR|iҜҫ' sN8(S_X–QqN5#N78SSk 1X{D~~ 6w? '_^Icqk5R^5ԴM:^Ѭ-mmݷUfx8c %:-Ռp8(&)RRNR̹iB32԰8%)U^rcdU\[(GTJ*R8 9oO@뿴*\u=?ŽCB]bGQм!xCLi1.OϭjBS͝Զ6eoTrN+cm`0N熧gQC9Z&>ޝl4\- *U#8f+V>q擧YbҤIF0!7QK:: (*P~Ϳg}|fmR]^sIx-,&bѢG gߎqL~XN:4FrxuUK;rJI'd،}ܥRn2U(NsIStJ!qoS~ O-wᗁ~ iZ < |7oZгlm EiKD[]bDP8,fYex_u%V_VS ԣV<>!5a 5 GN 5?OEXU)輷*:U#:ףJTjԥNro_pA E¿$"U,B-|;w9vv Z?A|/>q%.T~eG/SXLF)X|GUq֋?,Set{E)C0,?SX oMͣ<դ #/J:/<xW>ti5W)qs{9ob=sG[/'jwp>q6Ĺ&'1 +^_WNYռa[40ؿSƙ.\;=:x7C*Jc[R*PR:3y%s\VI?džjv:ϩߌ5qOy%|Km5\iW~MΥҖMOSTMT0GVm_NQ,T#6˝YRa:^ K ƹphfu؜jxYc9$bN?d 4֘*2Z|K৖_<w>j%QoDKOX-W: o5jW2Ⱥv^XFD>1KL,+rƾ1+Ub=;Hb|uR 3s5_|GNu 0 V1BW <K:😧Ta_=oz͇Ąs^/`]B2)ԼQ}CMVm?k+SXVԒ%[_xY|Ea4kq>ȕuu5k{1>l/˰›O'MXį xu<)qO?>X;iie4^QONV÷x.rlb)qn0W?kxiG U+PxLV)SUr8'ְLWI¹mFE]ibIO,zXF? s,l~gu-8)N86SOuN/7S9-ׯq yyͰgOxT(ʍl}jkB:T1HEG*~I>_w K^3'īGԵT5-&}R[MRT/tCm5H|ʄ`0x<^#4`siiRԖ'.? :tqu%QRi1N,DmV.ʸw0q_Vͱ0&'3"gEf+ G <&3Mם*`p"]aFyп~CK2ʱ8k 0J ,ҭVN)ʤ*/۝:*YP@P@( ( ( ( ( ($$LW7Q10Zxz?K3ğ>xOa?xRqx&{O5K/Gٝ1 0ubgZ8-wJy~Zj,mOC f*5p,0a1z5_J!R_:֛]""(UEUUFUFPp1[mwm{=+hKDAԀ|U~;x'>2͋ZE !՘fM^`feRLAI* 1XTaJ5+aU4R9E'{FS]뮷{yesg8ҧx/>HshM.tZ~aZUX–Z~m clpZۤp[R(DQ¨/CnNmm+%w$-:#sIʥIJu''9rr&ܥ)Jnb^ ͌z_|%iL."ӼS~ )Q;JF^}V)SB:i 1F#N(6NmEɹr%vۻmˣcj|f'ӤbkTURJ)MSTm:$ȋ$r+#dtqղR0Aj$$'FI5$՚iZ4kF`RqZqviSMY{o jz~:_k𞃣jsޡX[]+ 4$ѣᇣJj[4i”gguΡYٮmswb\NveѢF/S֝:'oVԷ{ݝjpP@qZo^%֬I?+"|{[𮇪VKZ֞SĕJYbcF&VN*jdgka0T3,} ^okR7¢>k{w֧P k:k]g3]\oVԴ O$PKuyi ԶĉDU ʟ#R+GFURjR4&H'4$gE<^*RSV|SüESTnt}e'(rܷ*sW;h|q+6-i7x;Vb5{+ŁI1$'8aS (ԭVpJN2uwӮ晖]>JS0[!ͣkOM4i}ekV6znc [Yi}6vVvkkno kHG p ;ɶWmd޺$9u'*%)Ԝ9sr+Rwmwr!@Pnh!nmJuPk6{ !7v7Oks* h2ݝZ4kץN6pN5 I]tv|N# Z%z\E'N֦*qWLǃ%;t9Ɖh:w'åZ[y`o.>kcNRu pJ0|Qޮ_2x^>8V'e׫(ZҝFwʛEL Re%(82IQj4j馬֎a{/=cG{i6.=X[ڬSMq*į ϗy Qܡ2*:q*ם%Bu"΄fF/~TF*m)+s;ǡbQGX*a^V+Sj˒i%dnU@P@s+4OhZ74[j5.X| h`cB[`ѣ^*S%%R*JM׻xb0x_ ^TUiJINϨc~<'-;l4]. 6 {HD cqZ%Ai qn,"n۲~nK+OWb*;ԯRiUro7(0".-" yI ,3E hXْHYէ:Ua TS:u)rqn2.)¥9ΝJsԄ'NpjP%IJ2M4i 6z=#z&:mؤIq*Y|6v$< (idwvkJьV#NZFTaa6bI%b+UU+˞"I֭ZvKZԩ.U9I)]%a<=.DFxE#_쵍.` F I0 d-Fʭ5^*ьjӅH$ҒSRJI6J6o k,F ׊q|-zzR* Nϩ+q~ރM$-z>qK1Yc{[DRg 'P)(ӧZpJU۴UXV+^xf&/RRy.ze*sIhL( (:usWCo  .@B*J*UgV8B>yFRJ_[fk/c6Qx8[ :*ͶfgkZ@rxcR{Cvd-l64t}i::d,XGr-^v2Ezҧ +B!Z#JX1V$ u*+NpI1SVi[<*N#K~Nx+~({Ogs8nUok{^2[#no hz<64V{!.-!'\^**e^<8:廏-G5y^vaslFfL>!޽ .3Yޭ*U! ݼԽ"FjQFUW cnMMmvնm}ѬPehuYIbۡbXPI5H*Hmb$WSW^WRukUIsԩ7)M$۲K52*_X7feiiŎ_yccwAugyip[Z$[r##2uiRNTSZ,ՄjS(M8]lս,(֭KRz!Vz3*jӗ=:AtBIJ(]4d:FxL4/N4m2;=7I,m3Om8mm-_8 "AªӤWHS!Q#B+H**$jկVz*VZ֭VrVZsRI:*NR&97)6jViZNjUF 3T4 ugw1 ѥ^jTA*5 ٸ5uO!Я_ Vժ|P:UiUxT8;^-='< mseWw O {H `,`TwN:0TӅ*i*tAIQwewdݕdmaF5تyjו;y+'. ( ⭾|:45ePV:8E,-^oaR4g̒R振moVǞP@P@P~zwzniW/VP $ ݕS[\DJc'BTQRdRJI4WGJeqvj]YOvTgs~ui~ׇ-;iѴŧa4kks+Hc@䞋NR.&o*m{+/#)F1R$rwk]-vt%P@P@P@P@P@:恡xL|I>!ѯVI4=[LU`6ZΪD0 W*h׊z4F2SQN"iMI)+I+}yfpHNHƥ*tӜTRxNgexY؋߄o xDΏK&Eb\dMI$ b FqiA+By!aae[X|. O ӣ9|RpY5wNzFiΓKl:A0]5D&9t$TVuiRN:u`nam;%(5t^ϗf('EQzQ$djhS ?ҴxkEt+ 3YvVrZE(BiS%8s|\^oe~TmodG c78S%Jbޮ_;ˡ ( (8پ|>,~4 14o&Ɖ'chdM-#D$en|@k*t(Q:hҥV?N!R?8J\\[sU`קVThR^:9|r{jtP@P@P@( ( ( ( ( ($g(p{Ċ0#PFQ:n!~+F{[8o:Z=AMwwurQq4pz( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( fZ޷6ayu}w}u$Vv6Vswuq,p[M"Fˆ+a8]haJX_-:|=9UZ:pbަ(Vףҩ_N 4*kV5N*prJaE9JRI&GUj_SxK>go;ǿ/5 }OEeSo0A=o8èc~ |;KoB\xV_;b!_ y&EqׇOsaեC48/[cpF+y&_pGS/x东M,F [0owS5Y iVP!G:0SQ+aq%y&@P@q?ğ>2&?fOP}Q|i+_Gm/gE~X~ ?e_ុ|]w |CAXh.!!xW^}ŵ5GigU|6j c1N*aUiMBjs+RSNxpx#_^yO 9 9Ud#cY*.],:uaE2ו,FƼ^b +[oۗR^y2Y>CԤ凌7:oGՖO}!/泒[k;o8n(˱YfxXQͰ:\l.;f0V' G\,iNXaXx0.\ПW~*[Uj!ƚW}T6#-d]Z\Dik UgUp<{)Ra\3ɫb110ixkSO8b#_* ' g<;f9.ma#q q3dQ?2Uqx Ƅp,t0Tܡ?|3Z o^ [N}.UQҍҵu\~k[(baF5yҩ<&"V*j1zX ZZSW R?98t>32Ӆ*$%ITX|}2:4qqԒRN\z`}P@CpIoo4Z~}a~wĺFxŗZpѴL]^i5ܐi6 VCpR; RIO:lfYM88g^xdǖrF"u =*xJCVt/=c Tu)U)өܟwiT||O*][. 4n:wmj_ aگm.iŏٽ~+Ei;.4V|k,7Zƛi mj6w$d?LXYNIbcK%ʪVsV`h)˙ԧUXj41AN2rN\8j4%*/C-=vҏaa nj𭃆:V;߲'T|Ky؟>1cxXWt 6hxH񷉬0\xT`R@'M^춭7աzxdҥ<6'9T'Y(啠O, 0 s vQ+5t,Y咪cNLu[ ^7s@P?~8>|#օ=~U􏆚[TR~ߒ?ԇ&<<^7+({:ʅ ؉׋ R>5)~J: T7 ]k&/ZCھ^jڝxk٤wVfwwbB$8BY\Ҍ#C6!hB01c5'SʤR_ڴ7Kɶ&'rF+=#>,[○4+-?O{Zjn _in7X}?N[-ԮՠO&cdQ֧/m(Ѝ:J ԩ)tBHԍ5N Aњ'({Ʈ# dQ)81 S)TX8r?48zߏ5~)x?◇/ziK[K ;pOb*r1X OLx8ꑩ }r>Y_UF.c1zrX /l\KM]\w1yrW +%YNJ.lvMjsQ u~yT :1jԀgOsҧNT(PƖ+bjҧV: s}:}Tg?h/|(R >= ׺f5#G$,PGn/ V/0U-c/ԥpJRcS&V.;۝L$pO|V.*i 4T*`q,,cVRg;O݌1pJTڏ,c?ٿ)|bo|AjZ_ZZ-ZtK(Dcӆ݆zigeZBB0'Zz،B1 NPB!SN( b'_bkVZաJhPBuF ? "O9(PUsP@^ +xw^KK?|;nUk.Z}Cz-u<5ƟE$b1ҝ >"iε::4i*TqXZVի>yb+FPCRI(؜%PN$ւħ>zU#BvNX֋唽No&kW]SZ cS/wj:˯įƍqyy,4%m"V:N+ P8,څ8Wmjn0s)S&ەiJMrrwrrmɶ}^A~b|c{~|MsOT|Ww Pvغ_hoK\]J^SaNYF9eL ,F"*J[1:T1燡,vW:8cqU"/ 6T ++11 Fs$n1jVrR]))>O><(vi~|}xkk/<_W^_P =zX{3j2Dou6p٧rM0utX.^ZO VuepL;JlUD,^[VKm*Xƞ&4c#sU)c0HCЖ*t퉆 x_Q_~8,x;_ >"xT5usBD _xRAGÖ pb4ƔN'Z+2 K%1k/|qĺ⯄8KM3R 7o VU֮%/S-ݑ{/Iʦ+ҧZZ?kIrB ʼS/皜&Q>xFlΧS䳣JpSRZN5e$5*ZtM\yϊ |Jyo 7]nOcoRιhSTgTVxn <&Η/[ ùԄ+TtԧBU)Pu^#8JTiJp̿V*sB'U_U'4઼= ?9T3_?oC| )x(>)x– 5{ޟ4o hIQC-SU -R)Lv`0lZ5eLE\vaJtbt)Tj{'Rh% ،Uj^ cqXZ9lc:Xjtp֥iNl5I**ueS,MlG{ψ^gֻ''~͟5z} gNеmRS^jx{Z翓uyMwjv#3PҝV`FN!MҏbQtjA֤c)կV\w1˓˗g Y,DuUuMTcl3TUhcʧIэOcV 3ȧU9iS*(F\cKα 5qiSUƅ9>tE R (D~#?<=Xx _^\^\1wuuXʇ⧌9ܞx/ÿ|W<]{~8Gg]-IZtӤXݦydoW֤{lty:q#,Q҅/U)S]VG-IUmew>6>|Lmmm{xgEkK뺅yI jv3C4I9YkեJ,'2|\>,|AѯO wt'viIı]-Y2OKt1}'jjVc[Yuuqq2壈^N:rO\qYU|."OjTЍI”!K*0&^5i)R>S(a$}\y|U[;XՅlwzo:=h\6L<"\:|L-usG\k?5WGtm`D[n,-oI3崨a0G,>YW*s}8V[Q u)iUhNX80XN[Чj`+՛Z㈛/g}*_'7_!='|wWmCz"K{okX9?ƏWJjM&QUµ<%x8XǕBx|&.ScTa '4"Mbca EJs|%y`+&R:RVUeJU}j+JNWs` (?h-Ɵx0j&ijOzu7f.uk[.?:g ~fS 3Wr<(ѥ͹b9aZ'(QҩSb+ӧI<<ٞ"VZuk`Y6F1Sm*bJ4{Eww$~ϗW7ח? |9-]O+Mq;,znv'>lRJnM'd,)I+RnRoYIm|Q)K YRܝw$vJ1[(I%=C7{<)_N) &=gou(tsQolu|5iv~lO+޶uNUFYk`14%FxʎSstj:0R'F :ptq8O\¤tjTf x|-ROeRaRd#J-FxZsŹ`vվx~8xxƾ%5^iq~5WMaHsiK+:R< t\ 8Q1\-|F/.Ulf7>yaocFrj*eX4I`+ѯ]P**)BNp4J`KbG~?to~Jf>1խCE/a4U?Q-e[L6zTl]LBTۣGy9vKF8E.dJXn28\\':MxAMʫbVQMPͱiЧRǩʰqTUZsJ8 ሣP߳'e|nq+_P?^;񇊣^<]|2Ue0|~'k! SPe%:Ƥ\jZ]Iq?VⱵV^]QU3<])FY)`25'N7fZ"Z,4aUVN<<6JreWK.ԄN3>c(x (֫Qӎ& :蟾NNIw~fgy.^Vwj=Myy12CR^ּ? Z,ֱJ"IVʹRe*>ίj9WJg*T)]QkJohVꓤjpUNz|PJqPniSxYO_]+ a@|<$4[j u?J<5-5m-Qr=]?vPw>6>|Lmmm{xgEkK뺅yI jv3C4I9YkեJ,'2|\>,|AѯO wt'viIı]-Y2OKt1}'jjVc[Yuuqq2壈^N:rO\qYU|."OjTЍI”!K*0&^5i)R?>9xxL1|M,注|.1'M֗x+]`xukf(5崚)5OGKf{rfx$rĨˈU=4ƔhaաFgOQReL%:4N=x gyMV,U*)N ҡ!r\Naѯ(ի 5pu2g?A-!Y#+w/??c}O:m<%h Ӽ+>ԬJM n%mi^sWޯ= :s)K4eVgR=(:Uܿ-ۋ\\\L,#4+;33k81}B!)F1UJ1I-Jmk#[x5i%VI%dVI^9~Q\kl|S/ĺ77x~^o[Bg V{/YBƫcl[U2OͳB񣎎Q),>PcjETW<콤b1}Lάx(F'<Z<J8J9ױfxNԔ7SN\5]K$']ME{{k1;CNּxPu"Pmt#5'FhYJ4)FujBsvQgm7_(Vo|3I?[Oo[׾xb-M~T4,ʞ$Եa,o+_W, q1.e:*c-l.j1 Җ Ư"^ֵzEV+$X/T:'*P6)iΏ֭*<[nmCpSQ*q >?q!+ <% VMgFS U(Rl<\*PUm:U')I`r3 9?Ŀu3c[e67*ص_^\K>o VU֮%/S-Ej0'*< JjUjZx' t/*T!OӞjsFd O[3T,ҜTVYE{I5MJ֝8W0P@P@( ( ( _ i;J=koï? //|nş?V.WWZj7$5:x~*\i~i qyC4ub7(Of;ܙCù:y6SAq^nUi5UU~\0X?NWg[?^w>,~&|<ᯃҿjx<; q|3-OǣxrKkǰXg3%xӆuFX~>xi7[ب:*Œrxq~UW9.]^t[0Ppxaf}(ПG^懩i΋ZjF[:^jXj:ni,֗siym46G424lUiUV QFsVXJZU!.YөNiJ$+4ԧVJpNiJ(QdFM ̰ ('_ؓ1_F_Dyi/??3M|Va'7AG~5ɾ8?T I6ݒշ]z|S&j{u ޽{Nk.=ƱjmDxsS."h<<.j b0Lv Q(N*.JtXlu)NZ*V6\se\#KyN2IPK ecT~sbf몜#KK ]3ό߰?k=+[xuH'hou7ZZ$hirjZ͵NN (r|FEG.V?mJKO#]HFqSK.iⰸpxL/QppUUo6m*Yob^iKo]0?aE]rf&Wb(V?f7]Zbgo;VeqcFek1{xaM+Zx{74wiM*MVs!]Z7 _4`sF R/ ͂ե쒪\Y\"R.RjF-OapYLQ& n+N eJ| aF*"?fB_gd=/.#:to&ŵGų.sneҙF3N5dxM)]s-՛[x /-~=]L|oHZV:֎? 92_Ҧv/IY!ҖKkxUp~E^uaIBQΆ/֍\:xڙL-uywcqSR\1%:qiqq:JY`)5غJX*dyO/y'b~/-;!"M<~<"W{>=\%\o$qaԯ jʝ*4KF>ΎC+GBT(as4R8BrE['6[SRWUYׯ8ENzNI &Ug\#) UgN_ajd5g5: |z[}y~Y7ya>w5&S™:]-u[̑%o$v.(Λ}7n{sP@P:&L;%V;\UF^a$Sޱ (/ /&im?a.`0?\cWr3(תB>#t>~> 䖟>#Zۻ+q0c+US){,>gQJ7tp MU$RnS/#J<57>2ڷ\ed4_hiE i҂!\GXP@|L}?G5*8D93/Czr_eDK '&W Mw_UuYWW9{cZ?ɏT(# ''"_klHnU>^i%`?`xK݇7M//ouj tkkuO խɳ#A/e 2͎YiN^yUd0Yuj<3U2*P J4b^9J}>mlMtՖTcTERKxjb/jT, \Ʀh'COΟ u?'5kmb/7:|Z忰a>;-S2Zg"Gb+ES*Xaܕ<4NeB9vyO0C<jLK Su*:괪JU9',:,F'*A@Pߵd;yyeS#,'}dxWLogzVo+7x{TYq`>Ob>?yY]|UKZ^"-%ԐOX4^ ӑ^#f/4k7t,yaҾ#:AYFtezҥThң*,Jѥ$7JqJ?-JrZfԍ֏qjGb)|UM XNKuƤn2WW魍( )?xM?np__B?]ফx߰1d,<ӗۆ_7hAeK% f?jrㇷ_w,5IY܌惔' oTe-:YaZa3oTY|M[ƹ'Q|]S|Àxnd0٫(:-a̜ #lJ:>YU_l׏AM[g#VY[{߆7pCP@P߷ b,+߇}K[9#O?kI}VmKř/dk1>0Oh>,GG=fA6,pxn.eʅU\;obzN}yG,=^XjrWd4ܧ#N nN p15G?l^|D|Bz rMbQ+r%=-z=C"ۧpھTͯ_!|$>?|?6[jJ1/Sȗ> -2]%tsP/}8Z˳n& jT1:/PFu^lIbWT8৅Q1R/r .g8X,bISNHO y:hNt9,7_ԣB0UtwOఱ\yE& #|p> b7)䪓ԁWf&qTj5+՜Sj3)$ҺNϣkN_Ntp*UK 5v8Qdݚj_\ (BSٷEtχ.:?5-Z-~~46"[~tiqnC MNƅ̥7/?g! ЫxJ هU>-q׿O_ //J9.e$~i}MSBr\ݦw}j oypj8Bg֣x<ЕL&]XJj8RĪ/RiNt9է `{xLp!qMYԥ,-wU f;MJQӥrH9$'SMnլ|Zbڟx}O[o9Z|N_tsCo[jv io55f/g<SpSb2N\MZTBY^SxaVb1^ O.js`+)WקO,Lq_X]aVьhO ?x_Ƶ^񇄠%ńO Pͅ[m~$ JC,N]Ч4'[Z)+TxUN1qJ84M˟ckJ^&ʵ%CNe,f2Vfh&'S|iA@P߷ b,+߇}K[9#O?kI}VmKř/dk1>0Oّo b FDQ$y3Gna|\ݱuUq e*\F 4Z?1SQSOvAtW 7Z}i3\$s=rk8N t,|i{;nuO-U^)bq4! qyhE9l>+;MYF#~YJi:(<*8K篃Vi\JmwpwY#Ӿ G.kO_-rswQzr3-V|<ֵEK+:^'(ITJBޤ/#mK+rJ4(ͽ#'J.c-eN2H (R@o~Gg~kwEO>7wI VQV;T䲒,X7/ No*Gw8.JSx,˗[o:KXO_N|%bN+ZS<J7_+ʿ~WGc3\CxQ=G ջje&^.Ji{uh{🽼cՊ:}^&W>-afO "O*ϋ\.tf_B?] ( ( ( ( ( #V|kkKƷIk^5Q%M[]6Baf׷gHc+x^J|e| 8KlRQt01ظЌiӕjZGך#^qMrӜ018ê]Zg^Y8R<*N'эJʥY_;AZ8 J¨Tl+|6u߇F>ֵo mn%̛?bkשlj5KXtiԊRkN5#Z\*,#B.g*u'QniVSj5$)VJp@P@OĿ'>?'_b'_@~+?im{x/D4/Ř P4aciace["RC],o~2iEr :Y/xGTîT˫9{dl4WEy?hK*4c~)+SõAO0b3LU 00/ո{y\-[M،8gaZUxUS$gO N|3?(~? <{~(=*oh~ _x@Ӭö>ԼKO [-u;NY&O&+drF4u~Ꭵ}CImmwz>yOwqX}26+y{:ޝAccm|%|.y*Eg^eT)(Wա7O*e:X,ifgx,~T^xv;rpʘ=z,ʅlm fҥ˱2hnߎ^ 9}#cW6t~9^ֺwɧ|C}.5[776\mVtMͰ7/ƶb3/Q.X5kWZ<)X,dsS(r<ˣe>';> `(Q'RaJnJHrʛ\_N?ۯeF}ſ|_yFw|7R_˭âC>cSԣӡN*2,vXHe8,vGz*sJ*ThXu1+ƕZ1+b)uU/ʸ/S9j|AK6#dzGj5TU(xjգO*JC2.|cq Pyt3"|큯0wfca~Nê}b/?c0^Kk-u}gZouaCH/;y?m-0?T9Qd_ZXH׵>"Q7퍬|)oCU|sOxCšς<=6iO xSD^5ڶjWŸ|0<+¹eu%X59ׅ!8ի 5S(թa*=RjSLM,=h~~x ~Z|!aϟ!:.<;? Np^jg+[ZRRf[ΕÙ[p8| |a&N9C 3 8&ԍZ+xDb*ի?̸z~, +(Pc͈TGKׯVPJQjԡ ta pGS3Zd)>p_^5[6/ĚƇxjONM[ICs{x~}F=K l/ԿlpU0|OpPuVY <>4}zy~өJJxlV0z'oGJ42+ȩy tkq Tfo ԡSJUaQcrl])iߵ gO?ů[Jߋl;MG#ھmSP׷6 [Է/om75s<=xCWX<>,\F/0,kPab#b1fU+&˸[0quU#8|d~y*cVO 6b%TƨG,y|$k?3> h>' ] MTDGWUP@Յjӝ*1PJXIL%F NRO KMp}oxw#J%^vX4犮'R=u1xUԄ=Nu#h(ąb]  9)FIB8R%(Ԓq&6TUI'$Mj)[JkdG/9'٧f!=xOK> =e\&onmX? "%P2Ia/u',m[3S|[`,F2Ԭ%)AfХU/cgV>j}\,]9*VYujUq0XЅHNOO J䚗^r)Ӎ:ꛛAciT"*SVr*TR=`8sr8J^!^xcK4>3>Ÿ;}j?lYmw?g`0ߕUg{K~~O~?j i <0j6z7*/-|s|]IĚ.x[ }rY]Xb[ 68㱟Nie˪Ug.w:J2%sN{7Z (+WS4W EN9cN:NRQi9N ׼Umߎ49!+{Ckgjq"Ckim)V[[7kR_|ʲP*$89䵄<TFqO49P7[9c%J4i/K.yeE5g7ѽ&ۄ:( (oC,7??Sx Ҧ WuRKFjXn>iVq0Al#O;0W2GJ+,!yb)E⺘}ihɺRb(9#V_Ycru'.XiY0T*ajA{cpӕ[ջgTŹ'7B(s`ٟ~ٰh?%kj?hXJYN >û/ۏY7h^u+OX [ WW;ǯJQ0/?={_{EKI>x7@|'0SY\xoGgqe`w6mWH%-."k)TU!愡Qʫi.^G9 r*n Z0qSQ,^IJ{}ۼ,?e~>+>/Ʃi|o8>qVu_=nbi>dL^{2NOU*Qb99Η.._RT)W(,Q*FnJpR>u+cT F5%x~nԹے<JN*g¿z7ǏYFּ]cϏ\~z^xS[LZ\}yq~m/&7d$X]q*<?Z9Wv.ź)V xLghbRmG(VeQTxr0XAN fSbsLpT-Zӕ 4\%INՒXX/?i>'gKEτ_准<xoYK]kUU-oƺV[}&B^^ͣMl 3FlL0x.g UOX>66ԩB1sV({j^N-j%PpΦ*l##R4RW]PV8*.te?i xᾏssy }Awyk&JDKstu,K,#U@^;f'1Zs4i1IRMIFXJV .JӜQU+֩*(sO٪Nj<Td \]iVjWWz\7֒Wp$]^I*[ԱB '"WeδNZJHS:t#(BU QIF%RIAJ^rQMJ0JԡVNu! 4a)%:ԪMSsqe9()ɤ~8d3 Bi:?GV'o허ntGyo~OV\s)ޤqYcYJ1oIb9d͚: {e훥vS`9asH掴9GWi-e*>ߚMo+;ٿnNEz8{/ߟ_\rSٯgkK/+R|Su[oiol?ޏ>|`~^ <7jƟ-]2xi[{9/ynn)47.u)g6yZ,u 919f2֧)FT%:n*:PۙB|:ȨaWNJG ֎nIe{nJJKǎ+#:gŏKk oS]#ڝGQ$[ֵ嬠޳ ,v[:ҏרc0s^iVƔko*RjSR+y>YpXLv+S 7(ʕJNn/R)JR#5]Fp??a e8|M?ďGW,~mm4}wixU]kƋq]icE4o~ډw_[S¼ J:Y*1اW*,NzXu*08:8|^*]l&'Kʪco9W4#:JrTC V)Vu%_Wf/k;jדE#PX}KW];bݤf *˰Ml oml̞MYG11Щ2Xh^Ru,ulLʥZTpTrԫfUi<569~QЧO [BU^*t.|\Ӥ Cz6 (>7/ $M=-"1OGįiwFF=c>+3%kN EgmnWRxYz|/B*XiԂj s֍(AS:9OǥN1|]Jqb²RNe̡8pNr(Z|l> 8sC>ߏ۟w^F!?ezO?TTp-౞{[ wK/v3;NoKeS{?㽯""~~O?>~ן?{çԴƿu?X5-Vkm6-sM#R_V6K=ޕe^*3\ 4(ʵ Seq%JZ<vbqUײxHNf=`k†/+Ό'濴6s? >*|5xL/[5-+_ Gúw|Cy^%ڍUmO,갸zRpy5Щ|8INa#INVU+~f2 p1_^_`Ye xj<. :R*֥Jң9F3_H&> ֞_~(x_ᧇk < h>?.|9-M^+b%jmjw}֡kjviF#fOn[O),N\+QzԥKY{,h`ⲬBTdEP棈1pZj&-9֕u(Wӆib*jcV7 |K/S~ |AioRripZsZO5m'Q>"4ږwkmq}iv`Tic0<>":XixZ)ԥ(8)C ^eN*!:E|TհZS?V械ztiTV+^*B"''N5\L?t+ C֔LдԕI$ 0w0'8f*7VؼE|U^D}z>Tj kwX˨I4 o314%ԭ }BYtQhўYR-YJym*럲~qp} ~b*bo=#VU4;ǝ*䕯үk9Cď?x[𯈿Sۭ(u*]6K"y0ޢrB[Z5eӔ u*gҦQ#*9N.LE8te\te]*S%USQUaFteQ{Dhك??/1vx_Wun߈ﵽ.]6=goe6i+_2Fb`S FL=xWFӖׂ':SK 40|Z:UL]lU*z-# ]gRFoVR-Mя T,DqUN(N/4̳j<>2 FuSQ)ʮ&S~KNPZUlW>7d+M3=|tWL6vvv"m&Nn[M,<._.u)g6yZ,u 919f2֧)FT%:n*:PۙB|:ȨaWNJG ֎nIe{nJJKG~"F{T5ZGkkj3ovڏFE[8k[M=~3F*"88NI4 ԔG2mN\G9FTbӒBU'*(*~0791JpuP@?/_)u/8Ŧĉ~'4ƉdAs'#mK?Gy?2ì_\hv4#6BeeZZe7uG6ĸswf7]_sKۧ?w]~{kG_*x+ge|<9q'-.K!{w%aeVJqV+pQN b0T0'>*~> xZOG6vCmL<{) ~u)ʛHӭEחRsC=^ʣS+ F~Ҧ'R(RB /g7J\3RZSF#*¼+UCTua8aƭ׭OZQqZtq0S8qOR{ߵ~<_8>~%|7S|C_j^u*xjtiԕ|q(6\LU8U5*N~8bh:\V T񯃿l>!~q}._f*jZG┞0՟6>conf+H "*L6p x:XlvaZ ZE,=?m)hBpjUgR4#VW)V+/1,ʗQV* #)Xj؊5Tʔq+ Kc>[*W9y* V8#K)oKiv}kueawщTe}Jw֦"*?R,)S?`n'XJ8^a"|0R*TUGN֭REyq:S(}c\@P@?/_)u/8Ŧĉ~'4ƉdAs'#mK?Gyx< ԫl¥H,'."gg*vqb_c9b2JbiKؼ=N<#~|#AZ'x9ST%/ʩTjP ڼc5/eqqqVd5i3RyP@q>׼O jz׃| |J nWFgz}kJA{}#{k}S@8jE:c9{FӚiԬ2KhJQe.y\9=9hwKK>!h|ZodBD'9|ӭ|moqK}3Q%Ξ-C=lmO}8~֟NP9g)E1qu5T8UcK =XMNqQg"ڌI{QOѬ=ºM?kQ]^&47}3NV//W:\.a {<U m8J8{7[rʵ(b' xUNZQ|ͩʒ%E˝^BM;bd'Ow):wg™A,4ό>4}ݧuM:-{m+:&<Ⴚ v]$MQӦcuC:M)Tu#KIPV U'R4:xzsJ'(TUsRyq'SXoBIգFk9xVUY .~ӿ~hO*R>$ԾxE}/:S`M65mOMMD֡qakbj_q)[(SXlt(bШb\I⪼ :Ace O.qX8(RR،4J0U0ҩ*S<,!9O7b]v>#mm[Zh>K<8̫/-mL5;;[wLs\=fUO%`(ԣKUNjQR X(<*xaiה.yapRʽ|\~ U7/|I)<|el_u_9jmkvڞ[u+KBH6#V O(SXPPQIĹMK='NUxua])C84q5Qi֕haU/bac7RT*xXC*s~ :T2aվ%ĚhEknMkش+h[Wk;[0~YQX< !8Bt^+ƝFFp*.Q:l hЫ9ц0xV70ͱ+ZTNUlF+S٧ U1RS^ x\HP@{hƿg߳~sG>).i_þ-{O j +NtCqIuHn.mŽZqSTTRBqXjNUZ5;WpSKha}*QiE4]8MMN8')%l3Ux >,ڟ~|3φ2|Hy-zcx[X,$ ՛B-,EWY~1Rq9ejⱮ2틖&g NiSn~ʥ_o S*xjupq*'Q=7?iQNWjtMǞef&cAP7!imo6?SG]yaTחs}O3y_[_ /^f+~S7êyg{8hN_SyG,?mC+<^-of ㇆4ߋ 43>*,B+5 i:|1iw:5N7C@MF_Zթn/К X:kbsn*J9:V_QpT/02*…ocbԥRJ8: 7VެrT3*Is#G.9|0Gu| { .>/QEc\kZP d3]ܨ,;Чé]*N%VEW8ԫW*N0S8KRTqE%v*8jw)Gƕ;C_?'}S^UFI }ma"+Q!𴗲Ǡ_5ͭzk#kJˇ5x^jf0NupT32zmtR҄eN9T z2P,08Vpz2.H<ӯu5ԓ?  4 #H 3DmFO7Q.[O4cQU㋫W%JpiXGR6UeNTMp2:5gV S,d&՞wNRteW eW?g.II~5 Χj-iw ZjqttH 4rm MCRD$pkW[-䔰<[T9q5SNJ\z>IҖy-ziԧsb/ t'V8GlWn4Wê8EjPJzQUi£|IV\~ʿ?i 7K+w?y[iؖ? TVD7z1V$Ҿer,[l ͔xPu+YU?kTA*<tx|Qֆ.CRZN*UʗCFgSF c/>!Yk5:ki,vz_cXXo&- $'_Хs8RHOW>e}cFQIխ9yLM|eWNa&UPN iEԓB %NJHOO~'ֿm|95σ.9| Ŭ0M2x[ƌiobM0 u+f&Û+%wJ"ڟ/iJ'p} ~b*bo=#VU4;ǝ*䕯~$tk w+mGEhnm<3{Wwi) ]- DЧNQTF]*3s'(uhR1BsKsJS(Lʜ%':nU*F*R §䒫F-2Jj3Rz( ( (( ( ( ( ( ($$LW7Q10Zxz?K ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (( ( ( H&+kkhD Ifi QFI#*"+3J0F*򔚌bIy8RSҌboDZމ-{nrσi 'mic+U{m#28 1F%XvZrMӍU{);Fەkd۶};iyS7J+DZTP@P/IϏIW= q d5fu-`W݄᷇6Cmo$pFT Եm+FKcSI.,R{,mkbnc-ı XɃ5&(:ftnj%!'Q@`* $|7ms!_4 &(e.-@IDfnFTm\˙BZ\Wmm'\ce)Ywcbn'$T C,3DZ9bHd6de Q[M>;4_uɌ4)E(Z=SFVokzޟxDo5cJl5/[iGWvaH.~soqySFӍh{e:ԣV>9Tԕ5xѭ RԄFi.J%UNWNZTTǞW*uyҝjGރ^P@P WK~Xj?ٷ^ {ϰjv ֝{y$-3qi>ˈDFq&'*rpQ ӕiQvd)A(E(a=9¤onhN/Cv薭szGiz7zv4#]+ ggu5Ŷ>tqS@giN{Hлs+什}XIMS7{B^ݵvDutdUNrI<{TmWm[$m$m%m9 Οxc^..tmJ/-Lgkk+怡ĨO 8{H*{ޅd}ձKݗ$KI]ot== ( zW5+ 7FKyogNӬ$i( *6C YF YM YISTqTU'k2mM0ُҍHU{sӜ*FYH (3[J`HV n4{"I4[kva5rC2$B-aV )aRiJ.Qv9zN*A:sR~(Kq,_,4(*,UQNI' `m$i$m$I-m$m%}Ot?G^[o> ƞo3Vŷmy6* jr6-`k^z_6'ݚM=%d+ɴݎYb)&DQY]c(RI$B"BIRڊrQWm$dpmmJI-[odS|cNJ7FA4` \rHٓFN Mni>FںJZWWWdJi6Iٷ잏M:JC ( ϼմ:}:P^4{{YK巖f9/n{YfK1O.7e5N:¥E:VVԢJܰ\7\`=!S ueJOR/v[Tt(oZ<5sgg/xo@H]>Z4*`Y}u$)!/}8{4~>|Zm:i}yFa%; ~WjGF A9ApA5mh$IjSOfTk/🅾 ?<;Ϸ9{Zt տPR-P~u~Z꣫kG=ʳsNvS['muqsC"KE,lI#u%]Hee%YH AiŸ4iZ4ӳM=k)M4it4֍5_C (3]_IЬg5SNѴ`QomucLwro,B$$d*e8RSv\F_vcQ&ݓvKvw6\|EacKt,:ZjvWSOo!R@`8%FєnWںWWM_]SWЕ$f+vi٭l;4 J4VK< FM4α Qy%G!#4RBf mE9I+ݒKv۲Iyi6II%v$_xKŋtG|J2$WoMVW R;]\y#I3bjϕNϒNѝ,٧z4RStJWpnJ]ZﮝRYچqxjVo ={K֭|hҠ{|k?oJ!tySsJ:+5%"K=/voMt[k@P@yilg1qRSSi9>Owml-FRIyY7eewk?m3U}SFԬ5m6<]GL%wI-ɸ9dV8.IgKFv̘2,_+N[mHWv6^]M1&y"(y$uEQ R`%^Ri%wevm%鮈qc)=Sm]-tI%s#*-4[\]xXӵh'ɚ}:8CynH8*d8FwO\vIݞОhJ\ѷ4oE;ۙnufj__vw{iXZD_\Cigk }.n8aI]w"RUUҼJ++]۶HRvrzE6Wz+Efn xK B%.[Wx$Ol+8'i pvۄRqJVgo/BnծOk>_yR0 (n>\+%y\"1C.MG]D?yJ#P ;>ggkOn*nU?u˛Xs-U%nuf7^YЯu*Yui8ˁF!Jy(Q(](ݫ-u N*u$^Sbz=SW]tΚ9[ƾ u=\ot]_Q(4+V״;Q2F,o.Ṻ2JDi;,qD?y7N*-ޚӛXǙwm$wi?rae|ѭum ( ֵÖ/xYҴ2&TQֵM.7|G tgڭ -ԹF.*Rrvm'')ŨWi6+&춻wMj^cohڕݧk闖71{I%77G# 3QE;I4vihFW咕iKtW=W_OPt&Ro:35u sup` 蠜2)JQWn]ދ]^8Sj1)얺$ߒ׹GB'|Sdu/ k/3۝CBlu{!:є«WTV|JQRQn.^]oky{g{oCj\۠ ( -Na>jvZkKUӬ- xT ($rje(Ҍy,y\{Ewm'ɸc)_23M+vW̏Et?XGwYҵ.ftRu=RWȑX=m򺬄p5(ۚ24T̚J^/WOЅ(O>YY>W٧ggfTR3?Mմf .OOmM+ -oYcK+f[\G$3"H-aN`R)N[N m7K>U.IℹgrE;YB ( Dm i[ɬǁ7Jמ5O4 s<g Ne8AK (b`r83ȱ,l^5u#C0h⽍N* ts\G SX(q.2cV\fqpcV*\GFg jh>~?iSx#P5SN?itо&~zoHΧjV˦xGLUlu4gʾG珶krNγ ]ʔqZ|' XFcA~A 0cgeWٍZu8FCe8hxʻ0`::x58K{׌_p_ne}T~N^ ( ($$LW7Q10Zxz?KWj髭[>?o߂_vwsg^x>(\ѴXu-8/ht 2`Zkj3 !dw ai)*W5'~&?-W*F:(s,3|WqT䧆0as! MRtiBTR(*Jj_@W[u;[d64pN03abStz:…9UK勷SZ i:ӥݓIE6KKWxKjxf?h;߀'KtZFoyyxm/nTun[X)xRffy21XB*SBR?q_9SҎXBgŇUer(9Nkxʔb Rq*8w? }|d|;rm xp|Yq&$LԵ#@v):;4}AO"^sTe ׯxʆ*RqRO꒨Z󜲝)VO:Iޝ,;#QJx 8bp-/ῴa\Se:y.%ԍtԖ2˰Џ(J qw?$pۦEВ|]GC:ץeO S8qȩru'taqyJܰ㇧.iө.3BUQ5J TqpU0////mU0* xzie\@Pg+ v=4\|YLm5 O-|g☮M_oЯ@VlaΊouy ɹI@XiUq˪aIZ0U_g9TucЫ*j…ʕ(͹PrъuQҏ/45HJIFj\F@ᗼnYG?\^I|!G<y|ubьW-kF+1_ۙţI= :8c#iV\'Nӝ4)m]¼S MrWe^Լ1~4 Aִi P\΋}[θ)se#t7PiٷM/QO4<>W1; '8,dRp(NTvӌᩣzqҔF5a~jnQTn-]JԄ!QBqQ7N|Oj.2pd[[Uwy*d⏎v{}oƐxXGxrzfB&WMvt& u x2(eY~PaT*5UUҩuAukb=F᷅}2|kgR#y, D6~fYJTX)rVuiVsºs:XXG^+?R)ueK Ru0z|P(QQkU}fh{jbwc5ԏ-ľss,<+#Hĵ}&20SХNiC$tiF1JsB8F181QI$H榳lU:V. jRZiVrR|||Nl(( G*)wgt߉|:񵯄<+Xiƣ 7/%VZm卭Մn>g-,V*USל&{+9·.HR2FkZ[*,N# Nt]['JTU*u~B1 $< ?݌|;>~yes_\=h&]^a꟔~#}cOCEGŭvO|]Kg:o4eOGFtmGk6\eS7GW ͩof1Aʭ,7m%Pqj{\F\µ\ x=s*Y<11u'_-beETH֣>kFNZY9᱘r~|>?MgW*vt ˬh_R׈ѠZ]6Wkizo OCgmciՆ3W`깬/W熤N5pxz4RSO`֥8<>3ԋRx"<*UV7gy6/թi~ҟxƻO x9 -_x h7ִ; SoxwSIOkF N8<5./ͲE7eS'b"bgIhJ?Wԥ#N eyj5X˅)MC1Wa*I5P=hԣK1a\jN%L?IF'⏀}hvW4?֚[jΉ[iZm5M%ţKA5Ԭ#똌7˫ДT') 8RSVU %J!)J:8uF35AF;^1BRap)qmcc^i9EaR؎o_/᧏u;$u/x-4*^{HвvmfZx2RXL~/ O|kԧ7hj1JO7}NjU_ZQVTQY.jЊ0өŵ%)+J^^yP@zޛ&DZ˪lz։-֏%ɪiZZC4[+h絸3|@O >&|L{d>/|Y wZyZYHbċ;R\f3 yNywï Ǥx>Y-+CX;W+]ico$:ԷdRL6ȪT2՚YNL&eKO8ƍ,S˰EA9SkntR++fԩ|m_rk=I*ܴJy'2jܣ ¯%@/zƿ۫s>4O|e;'~H$GT&GԬ|=c\i7RCKy7U!b*R%Haia1XZۼ<0s7eWRhB},3(SFUSZ6 tƅ|].QD#DžZ֡c/R`ǥ/k*W"ȑ]g5VB*NtitpRVxiJDi:>e/s+OXŽtU0l(9U*Τ*{9~1e?d#|RO_閃GNoAJ{;&qu|F{]C C`teסRfY~2Y)*[:tVRd4+qձ5~Z;T+F2 c*c*pFY(%:npJ(pÿ>(?|};P֏5cN*_j<]xHO4x>칶Ѭ<;qekfͺai˩}g #Jukj:xeL:ͦ*C3[ px]\fe[Z,¥8ε>L6# :+ҧAS`WqJxRY{:g0ѼgO~ڗgO4O}W2]ͦ%?ntY|qiZZe[Zuvu JT^,Lirө^\V&?WN 6*x:ZWVUk62u} ˸ERb}I5l&#NEr+Cˎ\hg Sq5kW9P@~<f~7;+Ku.5iNjNG.uw^ wS *zYE(Kcԅ:؞ ֍Ӆp6j{E[]WMR,F8ILMft23O SINpXmSUQBV¬s;7~?QO> ika?7?í"?x_Hexú\YxNhbHu-mZsb`s܊׍<sܶSjk]lUԕUhnG+oޥVͥR0erYh14?sNuckb$>C.4lOsGߵoݬAxSǟτmw˹}WXּr\:etV woacw~)SfU:ieըepIq+ t2S1+^ЄJ01T2`s5nMb2*'9Ftգ 5/֮egh$^{> YW} R+ھ`'ȱPG/ҡ{S Aⱎx!dJ0X]< XCϣ'ټX/m"Xg9@*P1RqsRҫJथ`]j2# NVGn<&2̪Ex<3+KkrI(Ja%OG 4'/xS>|mo+hzgEtvl|W}+SgmƠdZokc d,2O#?k,:5Zu0TXu}5b ,el0ƼT긅*犌gQ*"Sq6Jr' wŗ>1|DԵo IcvzCVNjNMBH'5JpTiX:xJ1#[ttTJc 4'JK˪6YTYea}I9Nt)Ԝ᱔pVr^teܪjOx_xOgᯊ Yۻ=*CM h utXeVl3ԫO]\^]:r*C p\]HT:3Zq FT}\99U8Uӌ4UiQ=qZհWIYXU:8ezqg'/ٹko]?/2is?x:MOwbHIGӞ}>iJl"X,J4IV2JpN V3 :n~VQ[Z*8SՓ է#7US/NeG_>:DY^Tto(msjU>xVP="S.ZIN'}[^=̢tSC̪#oiyL.!Ƭ1'+կW%ajgYLgmXzL)X內SBGjQnúPb_ŏ;H {GA{tqqsjzeS}[dҬl,^Ij_+tѬ]C C`teסRfY~2Y)*[:tVRd4+-VfukxfP 6]` d•*B׊.pY*&eTgR-Ʀ&Yڧ[U-;SX'$CvoJ࢟ |jo oZD`KmVJt+uK'iZڵy%IYUx(l8ت1+t39܎xxP9:,;TT%caMrm9VQիzU[8J4pud8}ïWMA3K|||W|3s'Qtk0Kaomxٝ;Gf6Z-LQ3^ U!G1YVsrXleYԕ5UA˰^ʳNF]BJ42S1)ʜNROՌ)`h9NP^:\Ef/~şO&e|qo~|i!| z,4O>+{(u*]P ۤm]Iy#%RL.sL% JU,ʦz<Ƅ~d{7'TrW!%R8Zup(KQFpE<>NF冝K,?Oo㯋< xGDŽ7Vx5-;:dZF>i4e3E,/. \IiC K.gRTXLq8:>~/GN.?noBU͉>m9ЌneGORGJPV4ӇŚ3ভFxcO¯|V+xZ;/^# ^hm<hto Nz^_2hmz]#U[U]j0zң]9ө:HskpU2cB&=JU*SayaCR#2:O΍<5o*`q'-z~&kz^e*O{3vnfm71<^&lMyJ+֛Isի7R&KBhPG F?ď ihlu]7w4Rjͦqg}w_HnmŽfM F8J8\F0(Ѡ긼e<&# <6QZti֌*2aWUU<+^^0I=aN QONJ1X~j*qMK➸co>%(|GWPƷ~*Elϩo $0%w{YTqjTcGa |ʋah+a9ΥGO [ RrE{IJwu ѯ.zJ si%O G՟,!B<e0l7LHtkkoZ$m{Zj7o \A56Τp:_8'VO W9QNu`aZZ5iQ016'R*pxY׍6%*ҩK r:s,F"zFPNIg/ط/_.^>-~W/" DH4x5+'=jcmZQ|55ݥnC.;VE:O O9: *YJ0IxF(5<[GqN29 mu|1Ö,FYJy|Wy<=<\:N|_>  xs];@w_3mk nygMKeicyckokua2xx|8ŧgK,եJUp jJpi˒>j答s (QVኩKSVqiҕJz߽jP~I?b`u}$c'_Ye_\;>W.{|Z?ɿd~Wz@P5~:6xcL(ih<%BpR n-Fn?o ^mqvix|"*-b3vNpXP(9QjY$7CSUSFO㱸yJa _]+Zҝ|59B6/3~߳_VC<-oTмgOxH߈`]U5mcMMCQjEκڵFKs=s،+њ88ZXlU μ2BAa}q=jT6\"OJze>2/,Nn"iԫ,M naN:o&iyלּ]xn+OL.cNG[AԵ+[˦lnl=MFIԧc8lUZSu#eJ囌=E)׶RT#,T*p*8,JEMqNqNhNJHʞ%Q(p_ <+/k>oXv<f,eG]Q. Շo =2XplN+/`s(S8Е;G/JSŧ 4!8ba]Vdr^ QRy,¤g Coի)F4RU+U2ӕW Q ?x EO]k%Gþ9^[x/U׼RKNnkqs~RM,:%e~T0ج–Uq,6)iƺ7HFXĨNy5,?:[ؙ5RE5rBBxj4}1=W,ta]&!QcOcg :m#d>'Ɨ9 5 /gS54Ƭ2%g~7y9k8yTI2ek?g.yĪb5YLj8|?j[$m58 eec}rEVis<*ĸFYx:$hܹqb*"ʱBfwCpen9os$ms;xFs zy%zm_4c'YMr>?cO? ]P\ʏWidS2W)yml·$0|>׌eA{VPq%ҧ80\u?g?g ox^>/wpIŤ@le䚾k:>YMg֣i嵖^=i{lp.&^#JBƑڎW/Є15vaW6:iNG$)sA4z\󌮚$S}NhӅUgzRj+J.[SI1W|@#*k&زsol=Rdǂ\񆪷?~v^oi>+vb[ dWy$.A)7ڐ:EԝO,¬(SR V <1N8Mc̸GEV:t.XTPU*5yFjb(IFv[qf/r_Dko|aI< QAEmo<%wm>_oŎD / ' W0kѫRt+3UJxu .STxV2"*rPUxʍ~ZԲ_e8j:ֽܸ:nPXޥ8Ջ{ 0hWFs+ᆏU5 O^, MjzX_3ëtA]N;roe-: Ԟ[׎6? s+O=.x59»^5qG "NIxV^IP@yů%_?xQJ wbPA#ܗwQ>Iɕ3]cr_Ul|_֏2c?i #7[kThX^ME!&{h W .U5<>swV%6 kM-l&&usUE)K"ռ7a{>ӧpIUz#^?$}1G ~r@|>=,=js4_|Xc-~-=SdosmiOo}GceZx'L8m--Qnn.$!VF5mK5!3 e»bEХV~ԡ(=e&md(RB%VuF0*&T}cc8|yR~5O)'M3#}C߰o]GRgVyt-Cψ4k w>->NwqskKŧ6p`ɝ(ЩK *v[0|2X#N.40+φJhN7g,LcjC0aGaکN8oV'B>RlCCџy:&xnM7,:=ދsi]Εqdg>=-֮4O4L,DqUV)V*2*ӛ6Q 1(,/$Qe\??Gʿ!~V3M7,#GP"Gmn-$ eigi+6$1rNO{(97Id=,J8<~mJݺm*J+[N<{vQg1?a_g=|ؗ />U;OjtKV?rG6 ݬS$7?k+ٮ 1'۸o8$hcUU0Lی+a+9҄Ur*?iE:s`*jϩu8UVw)Fm(;QmN?e$a_]#|KbʿͿsrƴIC)$~2lASHH9P;KUCg'8L튔L|O}\Bm{WRq5*.SX\m]>U:ԣ}UYsEP@~2vw y{29cvoY?l ;dL9OqN`%{XlEIu+ҩR5&%ENJr˛V= ^NFnT=AZ*Ii'$0L Ā98ą\6V$0$3Wˋ'e~LYr%UQ괥NwM&YْSuJ,E8B:s!nSM6HG[1C~6|h:τAo~#cnmi%HwNW٧mu=-[iX)O-̱QxcBT1XJ*BU#*WJ'8SŽaGV،."'TX~GLTT{z 5EFWc)QxbpW|[_<sssD-~*ώ|{xwči=5_hZO1Zkqmu]oQլ-"o:A |EeeT*'xn&/Nx 2jZt]\pv.Gq ?//5'T18R,4Ft*ƯzO :h~Xk۾5?~=|?thl*+x[m4Yއ9φn"СK[}. }*xwV|{c']cWGG<ئT槇*sKܪ9ø{pTq.kT`01OeFxj[ dxⓦ' ?{#>oRžJE\,7W`Ż\ 8[4G8JS BrTI+%)(&w-`1uTcSjF7QЧVj)ݨIw{os(?$ೖ7_maoe֠$nYHK˻m0d31%x5 (IЋvJƢha14╧ZON20rgV'a˽H,.h֎uwWgy г1 9Lwc=| ȳ*zn)Sr3F5&R,_ 1 J^2QGxRU7vJ5itWnľn!⾯MSXʤ2Zڲ| Ԣuw5/ŸyͺZt*˧K2&Gb,|hg2a~tGJj*Sa+ДӕJ^֔z*'ZGC={ Vo}n'P׳3՟0TQᱸOaJuaSzjnz?Y*4SС$˥^66nQYx__wzޣk$9$$(KW"2R;$aqu0\.WʌjnN>mT'NƳU]F:)x5)WԱ 3Vpy\jtOy/ˢ*&<ܰpX(J"֍*cVXv^سi]_ᵷf㿋:۠:%4{}*I?!kyghwڔm..$]MzЖ .Y*6qx= JxR*b0(<> ta)R9jGytYc3 3iʴwFjӯӂR`\?5uP@J3jMq}aHYR{_|\ywa,ҩA+YkHIF&2K&4RM4M;4i3qj:ak*Umd(4$e83S΂k(-q"]KpѠfer\BkcBEqSòQVW[QI#?_(_e!_3Gٟ拢ƞҤğgeo4De[}&Z/\ %[k?Po,ӝ|> Xp%18eZqR>[WFKN5%/?EQeq VTgN)V87VJ o[|1N\l6#^rjO K T0+UZuS*N;⯈_K?eW?uxs1ּ+KxuO~^>!x?E)in>6)$_՛6r=ɹ.!T"]u(izn9>"4Wbix{zuԣ8c! EjkG :ա?eC WG57,nWt֜' ]N5N Bx˛ C7 W 觊9bʰ8## UHJIӚPv,ӳOT9Յz4mӭNZm7 Skqj  ( Mcy/sL,m>1-Ͳ, n ++DE_EV[EYIuǜ#/E'pԢn0Jj-(9SUOӛ}TRyO՟ $bI=k?*?_6_?>?I,wqqm#+sdZ"\[L.wSͧrzK_y+?(]֏2_EK~⾩+;;3hv&xQtm2o*qoBڝwOmuraO`(P+bcapiԯJJ%om*}_֥Z.jGBqk<= ?g8FQ):s8_TJn?>8?xşfx\__?hxN"j k.>7ͧ[Sȷ&jڽmZs+ҧX`_%Zc^XE:\lF2PN: t#,k˪n8<% {8:JyfmGxjuFt_49akjWg^]+/↣W/'4?&_j=[լ)&]s:ΟZ=yk73jyfb|Z pXJ8<67 )NY,=*t_ MկG5eF*t0C/IOJlm8x>2rUzJWR|DW"8RNpu~p[)ḛҥ:vhU{/feՆ*HrҩR_ױN1px>s 5>hTqxRN*|t߁W~A |1{u-x__^MJMGAMLu }u}ufF ĩqv]zu2]z4_`s :jF# Xf68,6 ғJU+K>s™0T,E(ʣnee؈(ӥ :qRY[0(FC}/߈53iimCl{t ,\尾}{\3,L*ir}bN T'VF%^j:ƛ0c(Q)ƒN%_Z1rtpUJR%6|ѯ$ϊ!Ǐx׎u Ʒ;6R]iod\/%P.+)xl(K`ʣ)񘦬j,e,>'y:,y1Ṟyk5,^a_ J\&U9epT9 |L/RRUuP@Uk H>3^XM)e爾OjH6Wk lkђ*rfƙ2#w5pYpO_޼f8ocKVs'$eM(sNOTs*%u+wg IOc ~˟a$ ;'"Fy78q̳Vx3c%|Xa߃lOwhdO'ś%]UvHf.BKK*IDzKSoVyJ:`ukf?gR|iԧ-8I4>?W| Ԛu!\Mkm徭e-nN,l.Ks`n_aNTx-zx-I+5iBpe:^Z&zpoa>"J#%C.>^9ծ n֚zfaqy[Sҩ/iʽmJ2tkBJxQ}%aas* |+a)4:x<.[W *>ά0(ѩEJ\*ueZ[Vb14Kퟋ#L}KN^']Dմc'5;]NҴ+]鷺FTiuYwi_Afrn]Js|fժԧRJSCZ}aNSpl^+*V $B*iѭ)ҏ8J*_uP@G**#g\g(̤ I8#sc)ήJ pq4':Se[K2i;kNJ5!)%%N/i%$wMY5O~6_/TwpG97&h̩7eIOH, zJEZc Uj҄\cN]NQqQiE(J2qӝGVTᄄޤ]GyIm9k)=u褛 +iL?u9e yQ&̴UA;yݝEg+ƞ9}r1{խJ4οQA|S`P0getڍ:U*JFM))~R~~~>)>x2⟂0 |\Yo ž.ҵ[: =K;Ңo4[[Q! wB.cԧ:~;RpuxOYQB׶ΦcKSPlG2,uLa 9 [PPVg5!K Rr_/ߵH#!F G~>_asjZgxz[ _ğgԯӼ?j&YC}|q\9NloJxe 1:JLN):[^i)ӥV)@RB akbqu t29V~Jrc25 s':5U ~|ZU3ԫ(̿=me/$_?n5}V?%e_\eyh&?K=P ( cxRi{ MY~ ݇ğ^0 ,ReDYV;HL`Tս#.-dͮx]'u6_aO6ĹMaƌdWtk:iyN[ZgiBg x8׋Q-=,sQfE_'߱o#x)7VR]մ6N˛i*a ch4y_9Y. N?-ofϔɿ+=cw?l?6> k>$_AW mBqx^5Fckyr,+Z%Σdh-Ώͬڄw|&\elQB':C- R/k *SOa:NiVAtzp\ ,Vq1F QOo^uTg*J𣉝8aA|F=F||Gi g~(a.|:V|5{`tacxD4%ƣuY4z*JY]l4|aqu<­L.^TeNp8¤JcZ*HahF9,BFV~Ƌt)b,*'0ӧT|3NtS70|_↟>+x/~ 5~$x ?Pҵá24oluo/it|5} :ja< VL;bpyWgZjO)rFecQJ8 G(xGV50}>L:`m:4eJ)``b04ْ঳[I3P&@iElu)%]7>.l3Jqt<mW\naaj:RZ.XokMiB5cAթXxIשW E}{WXhR/ ɽN:y{}kp9RU#ejW{DӿejPM >2xLyah ee}h]ԸZSJp 0Xx0<~I 4 )_%~~._įiZޓ3F]Ӽ_&>-Xu-[/WGO/}NyCx| Ps^WS {29?c>+O8B^?1qf?/k:j.m ' f/ T…4牥G@д Z/t t úNhm"Ot8l4a 0DrI溱xF?b:f"/U\F"VmRrIY_Kx.a2$= JhÚW)1擻5 ( ~%9>*| eL8??gV(mO]qw-M+'O|$⾣j֗iyY[?M!\y:O/f8[yeI)*+`qX%NZNh&:S]-asLXƫ>Hct1\;J֕kDUKBq_haNޢikWnM H|˛<_w|n<+xmX _3ȫUPjRI\B:Qp'#Qu8ƕ)ڪSt:\.qUQjJ=js̒P=-J|mCnNj|Ug׉52AXا.|?fmJr|jb%F*l :t=Xƾ%RC?i^0Uʜ棶-;^YqU"sEJ0r):rJR?hOxOO%OK  Yŗ8Oዋx@uag{I۩0jEzn˧V9v;ڷ?pr9SRpuźnx.0敳lU҂0)*UW\j{8{JEZ!kK*xHT߳? _PwƟkx{wڇx=2; jkhElFK7U Y<:_xpYO*T05xaiD&)I\beWC }S-)d}')SI:+q8)7_wŸ m aJP\Cں)W NՌ!?ћxRmc(E*(cP2ēԒyUjT'yT'd)ɻ+%vJݭdqaF "4E&QI$޽%6 (|BKi#[ebi֣bHRx6te9sOƬ*N1ykUᆕFX/kZ5b8J2:W4Թ%nZ\czS؟iO#@>7¾*㯇/X'Ԇ9!M,ULML5\=oi:ib1~2Q[TN0X|6&VUeN*0RJRRԄa(?"߇>E '{Mn\Ca%Q\yE1=1#,iߌK]4:tShaS 6RpңՔ0RRsrpxeŠ%*jkb*{lEZ}- |ܔ҄ctP[vӰ1!Kc @$.q tQS{:A䗲U7S*)C)FM<˚7\)9([&nײm+~J|zn?>|Lne _|;xzM>.궚&^U ρ,vji0-`%,cW2U*O/)+S q+8J/՜1չg/r4J|UkTG'!Uvuy?7hD8sQŸ&~|h<Cb?>ĺqR<9ee&oM'O˩é=--L^V_^[U9pɼD0(9J:t8ST# `SJ|=Y9B>3J|Y6Qү[ỽ._麊Gwsh[6l7wC ʰ 9tqWZӧ3Jc^o_%I ,`4L^6IᧄRWWR&4`U0X|Kd𯃼9k4h֧ y }wsCh|F-}Wj*+a'R&?1TRq'!EԜ)ѥSGf:%N4iύ'֧*_é)6 {ZIUZNjqR楉{Ƹ>5xE |I5݆/m[ź^c]鷐Xa{S)Νm%cW -Lu  &3b*''T`4O:RV1WKiaцJS?i$BU[e)|W~?왣Iw?OXV[Y~!'tCP468t G~լDn{xn5 ҽ⣈%\>t񕱉Wӟ=9ѕ&7J~T'JjԜeeVNenH*39IS9F%9AԂCҸN (IKi@i%𮵡Mov:wC5iii󼁯+'Kݙh^fx8W`xORx߬M,dyegNeAUJ.0vO[<^ ,3W w*hXҤVSbO |!<~慯IY{౰uINOqw-ͼ^a#^ZU YnU^3vVbyjN-B_iabڔ>"k6ZX<of U*T%*5 ^L|~%M __xģRzh4;Ÿal.4-KN:.,4%Y\gqՅMz⧉Ni?ҩ/oT]l4'98xV"jO*8Ԝ_#C?x>Y4j>'үњ/ xz?_ xV65ޗu m.m6<^37T^)өUUYb+֯ӖJ<&C֯R \4p,`0qFr<2GF*RKoIg[*5^SuNiJe[%VPn| F1IQ>ڗECCۺ*2/hFr%QB r\$?;h>'|GA]~ɺ.j xr_E/Zy*[[=3WobiWytӎhfx{Wx^4qhMUwv]˥ztB]Kuu8_+EӌcQxWNpt?Bt^#A]#ŚZ4#[w{xo-Z\Gukۍ6Yl+fҠ\%tjxr<%IN9{(_kRЧVZPC׌j5'V(IŸ6}Xѫ JX<({򭅂*ѩ 0E^1(JS)7k ?j/jIx GR&TC~#-4Z-:c*F9TNxA;ZrSO 3&Hӕ t,9'^4T|'=οg߀@/:ޭĺy͢xGqs1t,ڄNAxy 1a14Ro ZڬZƴ,0 UR!b0TVXE[_F TJ/fJ߼jZ<.LUlҶqZQ~ʞ M˰i'BTJEMna,x;g>x_>ŗ.waLeUu5n/GnY;bM6iWaBx(a37Bu%Z1Sh+b13t}*)Ƥiʍ<XeEҧ䫍ˣ \!**qS t# C҆rxJ_/χA㦾5?)<+Z$?;uoEl_]Ī>}_UڊeXIԪqU}I*{HQu' tiT Sxz42ssIuƊ0Jo hB^֬iUk֧ӬڜTj9bk_o&@P秏g j K|3o(ǃ&{txGģMմ fҴϴìX1 ]Mṹė)瀕\s UƼqgV*uf :sώ8iF68,G7̲Nj%VjiUB99C rPX:<3>bNxG4_ CI\i s-~+!eжx<9?=$Mus2TҎp5aSJNCŬT%,D(sqax,\1үW~N|;šKƆ.$S+Uk߳oWm k_MQM#i:ޓo-ԖgM%c zV;\SW̽3I'XiƬf.z2R508huU-^Sg=Z8U75te8jUhM QӫSׯx:>??xc_W\m+^(>75g>(}7JnmeӬ&t]* Ok{gՏ:00,Ue%By0e:Ju֩'^;ګF)\.Y԰rW deFW3?i[0pӡQ7ZrR_N __? >7|4|zKLi<+Xd!K8,R6\B5ZɅFiTf(R!T/0'8iڅgZqpn1RxURSj춦WJq&&xr57J)ԭը /J1VLE7O#m|;gO>4PHf{84Gtm3(լרO%k;{DG Ɩe,:ک^JU1aF1\nJң<+eU  F-|1ӗ2˚Sx\\gN5$Om-m-ml[[xlP[[ư k1*"UUZ+թZ֩:'-R'k+MeE4iaSB:4hSA]h$Ve(Jzt5W5bb18 "YFE Uӥiԅ8c#O֑7/7W#ߊ)7u:YtKWXnuEYڅ%hAooqSž;OiՎ :N4ib4N-zt]Dӧ8/bZ#ZeS'9V M*PRRBTTUէ_KISRaN'ʟ~gž Gq}?7Z?4=Hyy._E+?zv| /mtoQm< ZU0H``ͨq:u&wJJL6TƵ(f109^'b]XjXB*r ߺSƽz0xV7N_?gHeO{#Q񥮏־&VO~'zqX5[hЛP,NkBZ}ޡ{lWbjžцJu_U*bg:،LƄ5=:|utq1[_RRt^ʄjNJ!N*5ۗ=zxjUwiJ|y/ ~lTckQmƍ4;:AU_aIOG"~?#7'[nͦVO{)<}?My)&K}3L]O VS>f~aU`>\!ASS>W7)F4"2jҧ*L`**ile|^:3J9VT)T̫E0R€ (}K~B~Z"C]|X575A9k_x?ē躾$cy '5-ɨY\h<N`^a*δ4 suAҜ )(-RQ08[bOWSG<=*.>k!O :ScBԥ OHB)`gz2<;2*n<jr N5TUJ'C2,kJ}qpWR L8(raW Z*2 xyE¶Rg~)|%V-'š \Xi: 卧좲\=ŻhFRƩNkqzx\.B7iWUR^y V9 dc!(>[R8μeK eBP75hԌiżk>.~ʞ-jC|G񅧆59񮡩]iw:NizVkU4{u6Σ7/,b=&H^ƗT~u[Uœ'p֯W, |=:aWNUiSBxjuҚJ5q1XƝ Y4XB"*"UFTPpDܤ۔wmvzޭԈB4 p!cdRI$]R((>pgM +?:hsZk~4+ZnCsi*Oup#4V|[ݘ.Jaj8&8,N.j)NOU)UX_bgAQׄ*XQ9ayaq*)JJJ9I9QP[ *!VS˾'o|u'5s¿]E/KSC<9qfNi~~*6.嵱SmB!c iyig5')Ӎv ЯW :=zʆ"I,6UJ]ɗ),<;e0<-lMiJue_  *ܱ0%ҩ _/٣g?i^1PN6}bP4)W!\)BQ׮"6i|I}KZڷ-S˩gjZitdo/ݻ͹1X/-20"6L<&.xXaxƚ-eG}ox6;4].KibMЧ,M8e ^#5:qeF ^ C5:gW^>1Yga+j8l+pxL5JJНYQ֏r5ZU]/i?~)<;V4n~hz6=V]K¾V~+>=F_ޣ[]ɦf qC * $0tXq8F:NZN;ӥBU%B X*ucZ3Q8^?_[-*RR*iSxMVҞ5фkƮ"im:u~g_˿?~}LZMqėEmjKuۻx^HVElD/u_\t1Qʔ)R EahTTU~ҫ=j֯^jZ 8|4hsaN^b5]lEvҌaN*PJ3r|+W?k (?9/?_O 9h~v6c׈]NV9g<&N1 R-??ӯ\vƻ wGu2=J=OX??t{ __]k^9lZHҤuqmQsU~Vˇi<Is9:x.%:SGT)ӅJ!k)ΜuW?|h9D#Ra,UlGeU d˥=<8f2)e/gSXg 1X^L?:*d^V>+}bNa.kA?n:J|U?g ʍ/7㞍bC_Ѵ\3PUq,|9[=_OKMZuo 6#q55u#seή_[M<JT{' FOZS;J?[w.2QN4%թi6 1s1 c*6F%Uk6MBZ~տΛ i2?Ui x.uxNľ3-AL C#E3IiXxwN]VcST1CR LO,Jp*U:NxJYU=lV?^JԩƜaNcO.~Iaf/ >ǦizMx}$S]O'tQ<0O6+ƽ6%ZUF /G ҥ |1TOKTEW hn9 C8BУڜ!.MwXg>/k3 11qaiaCJxk7p،MMFNS*hZq*l=ZeZiǑJw.quiURxS?/cۯz 6[/<1_jZVԆ[Դ崍tNM-9>c<Zj4NSnT iҨ.|UV.u’_]T}^n& Īb>5>8uj4jqSrOxzR'*8ZXzjU?*Ҵ[Εm֓Q:L7pOo{AEln'VQk{vڕOm͟SJ0Pӓ&04԰TV, Z'J4Y֮80ɥJpr>^*.|MLEL_/a,D.t(Ԕ}V؋I?d/x0q%Տx_|tbO>^6?Kg:֡junm&[ *O3J/Ʃa֌gHB\%z~:} &E:U<%*媫~btq6eJQ楎TzXuCNj7Z2qX0zĻ_|/c >|:wᏂ+i_ωV9"Ӭ۸K.ҫ,F;7*ٞ-B 2O *^<JqN*#b곥|&S<U!V5UuW^:t|iAJ,o,Ҟ?iğƷ?GM‘x_mHz8\N/U{Knu}P^{ _l XKXN*LKs*z/Mьb9*Z1'?Qӌqn|8cw9~Kb ڧᦃo5{kquI>Ьu Zkok5:v˧< :~8VD*Ib){_S )Ɔ[]>lt(chHԦW,m?ݴt \kVSBe9'ú%3|@><)}ỿ7:)x>kK_|kkB B {]6 Kh/!- z0]ѣ9b1٭ES5ǵ*TN͵KJJ/aJjK92H,6/ sue)btҝ8eQ:JX/d4Oĺ._֟_ Z|Twcz3Xy6/j&;Rt٘fY%ipU\!> I~4=;QW( ~O[<^ ,3W w*hXҤVSbO |!<~慯IY{౰uINOqw-ͼ^a#^ZU YnU^3vVbyjN-B_iabڔ>"k6ZX<of U*T%*5 _5vP@~_!+V Ŷ^=QA&}2_ytgַP::uķvwW6W^v-/*<a=Ju0՜*O-{NBXqRٺU*E!ivF*uҫ )BKXE'i'Z8<<)3?kY| ߇_j=/Q߉} Qy[_X]-jziI~m.n650C/מ)SSVzĥ,*GU%tZKX<-jxyPf;y­,.&êNu9t= ʥ7^/> |Bf+3| x?þ ׎hƙGĺ-*K۶Z^&`\LhHRr̥ѦBZRT*8zʞa90!aa Vc 5ƝjtSYIFJ؄ƭkFte(D"~>*(+?w|[~rœ^jRE?fR5-^ie&w j!Ԃf3s̰YTx.7Х 50W*h{jTab#J*-P,5\Xv]9brTG}oNZ𱥆7?g2_|4X##G'B'-މcqnf{k>#SYSnyb)sUs7$G:T"v)U(_VAMC ^=使2V* RSӡKb=rm 1kV_W0\g%kZ Y'ҾqxWUFXEtR\j 4l(`2ȡ剣BI՞*QMNZu¥ :3ϧ^Q6WV(F*iU~N3{LThօ gOO?d xG-&ԢB]G]^_NL% fIa[u'[N7sbxa][-r`SONxC]ZJ+*t)bjRS#NZU="_+ | g%Eipyt乿5)uFU."}BXGH+ʼiƝ*Tt(P zINB:t*Zj<ԫ)yap ESYNZV':em#)>Zp|iFJ: ( (?( ( ( ( ( ($$LWg{O$ mc_ {/K HՒHUԫAS@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( (uࠟHo;#|Sw7W,^iL(2^J $棘UIB=8Ӕ*XEҝ*¤)JVܞ-3*JnQ8*5JUU(F^O|Ac}?DV+-u/Qu+;;bۨtfBOFʭ8֥4ԩե'(Ӝ[Ҝ'JvmҭN 5TyV[Ԫ:U`էJTdR/X BRVF'/@MOu]"_/i㏊m=_A[ƚxvi;}ޢ)aUUZTTtqSk/j'[Hί5){IF ejJ.kN*:UŪr |iU8:3hTz/_ ~>x^_0$zeOV7wFn|GjZ>-R;Xug$W*mRba0!Zh^H6*SϖaVIB0M;V ᤣVz-%\R Q=*UhՄx~ -OΝco k+xG|DԼ%gA-Ο7;4o}F[=7S`X,+WEV҅Z(TJ"4F?:WJ8gZ:Na88Gy~5'J+.jTeR>P?:IRjVP*Fpk|~i[sx:摫xc>Yd|9Yj0\5 łqbnmsoGr U)ӯ⡈8ԦHRiCR0UNBf^XZTq1UGIB9Nj]u)*?z (<{'ǯt#V&%&ML5?xź$Iφt;KgVygG6]ysln̹K()B|^"5gG BZ: JNXNyM R9I&ؙ8a|EY(Qs{8m;j'qRJ^UJYÇyY|(_C㿇5-6}gDxLjG[G,0YkK0]O-캔vZdiRΝY%Ne[ tU:3u(է*TN*ž"N+JYh*H<]990\)fYFO~ռ{'_<#%uZWHQu1 jZ%#eZ* TA)NZ2%*pRI*pVJ1|ի>Zt8JJJoyR)Ӈ4aRiӋMJI Ξ>k߃4f?%Ko|Nk+ǷIeMYEsUſ,WTT!}`9,K?g8өte/UIӦʳV8Ӕjp*N0yiJQrS85qQ D5 #C>.џ ']s\xWtx/D-/M֣wka&Gwig2Noak6lZuC¯f -;1a8jئ<ҧFVɾ%hU2zRRN^/c TN)N4l{sSjJ[T֧SӲiNʝJi% Pte/k ӫN8ΕXC!?ĖFtK[RY-獒XṴ{-GNPolo-.zjʴ9' J3R tBRHJ3Jr%'LVhSm')Ft -:sQ%f(^2R; Gſ__|?oό<G%c>ھޤַVik>o{o-͌7j"ib)UW +cpګb9ԣPYa_ZNth)-O٨\Ue5ZqBu}'?|e~)g/f,Z~l#k'YaԴ}VfYtFOZJ' ZX5*UISmI)FTGIҫ kBjsZuVU`VGJtPJr_x^Ht85#ȼsb"o|A6Ox7o'6~xL,"n6F.`|6F rB'J!]a(ԫF6I {}bʇ79NQ9ITgN:3֧J,-Rrk.YRQHNZq*G3×^'?[ii,f]β4kZkeiAq+~èkӮG^zҬ5 qZKSVqMT)ҚX­* ZR,+ӝJ.^Q#ܓҧ7 TxTکNp&@P|c~| _ xW_>5LO|-k^0nju t-=oMOy$0iqkm-w7vO_aSR*4 :t#Zti֔]IEԍ C*_'-b*ԥBgnjTӦtJ3pui{NU83K◌oٷ?N?mG~!})3#FΛxZأGxCq "eo*{ey`um^*̳ۘ5K:dE.gM+O FT犧ͅJK~6_JBUeZ'Je:sF5~W["M[ҮQMOo2uF&d h5޵zZԓS ŸTVVZnTҜ*S(ƍju骴 9+ũBRJs:u)Tե5FtF3?+/R{]SßÞh>",ΎGܗpiփOTMb)O tlƬe 9NPN*ε8΋R9Sԅx짎À(TeF7t:ERWZ(#_|?&[ zN*hإťVfg(0ic:7vʬZJj%iT8J5)զۏ=:8t)rUJSJs9iVYONnX='JQH8BR֦Jpk77|7ڲ1o%{|pؼ _{&IK8FJՓTR+ԍfGLNJzujO5NstwJ'iU,ybi)t)L|0@#y՛]Se)F2JK]hZ>P@i?5_ czxKpq_ 9!ΝY_^eܑ +p\5iO B+ץEbkBniMӍ|EGJ'8FUg.JiTqT UƖU}*|^~Ɗ唪^Ғʽqz1? iGh~" éx? 敥_MJ!u]/v?QJ*MɨQф䛌d⚋ڔ0REmCQE[.qM#%WS֎wa__`iIo 8Gq%im|9-6:ƸJqiƢ͆rsjT4gQ*Ba8G UJju0؊% TT5~7(YFP8N=Ҡ( jEZi^isjZs ae ^^\ؾXܾ×r/l?*W|()EV?a'CΣnq^N9BQmNZ6xHAjvօiziwp_i[wai%ݝ\[\кIjҭ**ԣZVN9Jts*u!VMF[;4viQZq$$%FHҬI6I&n%mKvBϐ/g2oH'>/ EK.|4o 8ѠXGzZS.tnth3OkR*0^XXxR0'+?~֋t*|8]EvXxr[?4޹RKm_5$pNSt*Nt>FtὫʽuz5v*Z1U#RT1puk5HʍgJZ Ԛn5)zNN F TPz~YMcoï=׎_ :>WDG}3žkWm,^OϨYV?c^׃~/?7íW6v^o OŤr[fRP%A8*δhԥV>Ҿ"9{WE9Z^Ғ:5k>ZQ=Z*ѩJzT*TnT[8£J0P9UJY_OS x uo W(薖pjQxy5O[^W v|x~Lh6s-\ҩaTjpLD.JS:S:W(өFPIM=U0iؾ^j8N+ jsQV:RЧfMO\  8ydx =cVK>K[K&>t/[Þ4>fWs_Ք:zl5[[JVw-n2V،=l-zlD:fզ\Ԏ\]8qtӭRܒ䜠IE{$&@'t=_ľ$l4/:uޯk:VZnX@7׷sCommo,ʪIεjt)ʭYrB.*rnS:pTRZ:TTRQN ]:s8ӂ支QI$)JRj0"99F1r>< ?O=?o:W}sM+5YY[w"8PRa%-"JTkr+b9>K(]TStQj3I*)Օ3cZtڡrX?#EӛQ?gwQªMQՔ)S.omnmlmỳ;[[k{kYx]%h6WFe`iԧRIҫ ӫJrRHTRp%iBpqdС8U*SjSΝHIN!4 Qn2ԣ(iӹ$Co FO<αC 1)y%G*)wweTU,McR:TVN(JJ$N8.isB)RRFJ0e9J);F1I%vݕ>9 EmNſy/x7/)]*{}^/⇆mu[/@iAik[YjèjpݠeKmBs~#<5HӨ*\BmL^*wQ|ʝhYMIE)J^~ONUi(>t x ˟xC$M/Nukzf*GIY=zn.'>a2qc(,N>9SkbNpʵ *3KJJm}yQ*12⣀qqyl:*81Nib' έ8WGWkv c\ۋ;O? };B!_+X'Ci7ܬn]j9~"8xlG1qJڡWG*P<6*'RXlB'pWg8J Ыɳ\| BW/F+YқFhTFyO>P/o2x_LΧ>2k x/OZׁj喙jfOkkiKxo('_7apx\N/R /baBXLNss9Q>/>Xf]Kc%pԅ,=,Fgb0_ש8ƎJs B3xoO=:m-&_[|*ſ |m~Mo6-lU!I7j%/r/pYl^ RkJ;_ ЭSRN")TΣ>CЄaRp'ӟĜ=aKp+*YAeSjN9f'_%Zv4'){:|#8C>&p9_K~-|QÝ>߼1V5clfmtk۴6MrDLcl+:n qgQ:5&:VrP)S.X38cK do^GJ`  OU*1uV)҄Ra'Oڃᖟ{jVhnK۸E"IlOl[i ].fg'hT\hX y'Fm$8QeO 5ҥC6>4kӧ,v_59SC87rQ=O (9 </_t Zu톭m*kkķ䥞৏嘘cr~iYa>meSJ4~RjTV&=Қu~i*8dyeӭW8ȸ{\?ˣƶQV׫ψFTMKݗr< A{M4i{SRJQiM;kTyş~3ſ/>x3Ğ9נbV1kMeq^Chu֡eoq{,wlfO/9Ͱ[1UKU9V:aӥhSu*VENrZcἇ9MÙtSgy,J0j+BkFz9\EJT+Na9ƕF%gZc~2]qj /kiw@Ka|g+ .,ͽƙiҔ$M?Rsi\:j,eFTT9f̡5 -9ҍ?gۗYYn| -vw X]PZ]]j343IgvD]rOp-RH)UbeTc10o1C,cjNX$ :79sF>u oWO|)'ԡ9~߂ht \XkZ6x5xrgK$Z[4lؘfXLN9')i%JI:xgG5g%M6{gΧ aq U10S YН<,>9>l<:d @wm#> VhWixRX'kKY+{-/j 85)ӭJ9¥*kSZ5է)SF)­*uiN)QrxV[a1 ~.bpNj5#KF)P@|+Q0/PKMro |-tG1յ/\v\[HWowiwZC;gJ%QJ8GV$eRҝ:,Bҍ9jT׳j\ΔSR%rgP9R8c_-'*5 G w{_rm_ڊh54][¾4n ˰/; [NyZ(.LX\Y_[]qa{ϛGJt+ʥ:X#VQj59GXU&Qf;-iaBfV:rt攡RKe sST驸QR̳*п j/5C/x{7{msǞ?4Whuh|5;-x[t-5CYƧ<=TV(ׯPrFkb*ZT!*`MNeOGM”kՔ(ѩVT)N?k*":#NҨJ/hie-~|XVJ?%zzk_^Jj)W b)S?rʽZIZ>ȥZJ:ʥ*U:3XvTGjUgFe S{}~)xKwtHeԵ&TH4+NSu[Km+I.#y"hӚztJw^~΅':?J}rzJ ԫ(StjUiAի7)SMGs)_YӥMN xDŽl_'|i_g>m>5 zՔvwiGe}&wrj[A4ڕ]vխuTtڌNҥHԜ)*PεJtiUjSR*t/TEǟKSWSq7U:jNԜ>¬MJZhuiZNeuzui0=̑[ZY[E%ı,"#2ZӝZ:t91ݷ_eкtV T:j4ӧ9sj0!RQWmsۿ7ᅻ7-?_ Jm<>gѣSեTϏΎJ|{/u<+ þZ/oiQJNvj |~Yu5 iLOanoN<1(KmdPBxqn2U֧(URtNj:Tge(&*rjFqJRRHJ#HV4it˿ =z)Yrmr^Ieݞ.6W٪(W|vd*w 쮵jɲiަvG˥ޱ])ʣoDGu|MG|ZkVZt5W&ef.ql;?0fk+{+lN](V(ʭ>dFuhӫ,=e.LN⨷C giJ9PKOѓ'R8TcV4kTsBzZV7vuP@P@P( ( (<o|g'U~j?;ⷂY]ߊmZ[[4ΐƫF8Xҧuq.*3bU z0i֕ 2:PqU<%lNxEl>'ܰH![ ۣVT0g Nq8ӔUj_ͷiia+_6vv_aHබ(-8a8QUW!~qNQ0 tQxkbI$.d %_h>`?jo34?`?gZ*8kW6׼Yi5G1ҵ}oǷ'j^>:Ň}JKMRqqbr8-2j8ΰ_WTp1ϸkXѠ7|f#2Ϫ t2iC,x4|Rl$\fdqu>N=VƔ1>a:hi`m?N(ط=`]|`ſ/Z/ß~% [^/4Wi]S/ŭ>^𞍡S^RĮ4<>+8K f|^)bqSfx›V%8L\sLb]yW<,q x %h6Y< [*3qr< jك;8O^[wmۻ6TbQJ)]$woEw{Ha@P/IϏIWo#/c fa<~~7Ծ~s ?[:`k=lhp1H}N[Y-i(PtgRk.M9Ebrp y? թNqZt29'x1zX2ԕ(׎5ҡR<tj?9Ic%?7«:+kx_&}[Y>:y#| +Fݵs*52-5Ce55̱ n+b.&X|$*qy(J1QZqag4Ti|"4>П=$xo◂4W[cOi 🋎yrSgL7J]IijdEJ/U0w|ͩ`Q{:JqZh/]Bܰ pϟp'¼%9K ь~W9Prڴe=TkRu~_σ?!~NgBjƱgk຋YĺfEǍyu_ha[VG}>xLE<'Nڬ%fgm]ό1E4j+RdJiյ=+6QA}wju`Kq8^*Qiy3ʔieMx&OJR瓝+#:6=gCG˞ABȣsZ_xKE{IKo-ec܆q|urXYljЫnWR2aRdˢY hWPa0ZQr<|P X5{ IyZ,v--a{okSbQXYv=aWΰL],TǛ R1Rpc04RRp1$k*i{:8L">f fM~?#t|t^b|/O7 凉:۷'Vo$a_S1g8*S'P_R0\6 ?aʮ%V"}9&8O-u9Je5:h炭W}c`c}?,( #D^?6Ctw6STӼ#+đ_GIsb. W_'9NYf;NKVJX¶uc*S'Ic}$LJz{&]tZ2MNVe%gox_cM}W֭^<#%UؤPV$VC FsTF PYNUO8䯕kW%ׯ^dZjOu')|O9:8ymV>\ö՟5.BB5voUÿnOXx< tѠ|GY[!xGC `F*$2p~A:[rZTVi6T3 MEd_V9iKqҍ tӄ)ѥ*S8BW Ɔ>[jG-[[>R|2f#~V.xkSҍ`< P/+Egu%K'B S: Ϛ*-iʌoR5?ۏ;KJl*ZFeVp9iFpm'E6V~sG쫭ko<_s}GR|;jR<@FZk[ԩB(PYMzJITp)}[%5ZBxZ1{NU^:K,gUzX]kR~U95.C*xK ClG~1G|85᷸^85F'n!i 1Adѩ J|q+ Yq*q[a6KJc B0VJ3Z\EN|\!O)Qרe97K2'U9)թ)G>? ~=Yֵ-RԮNX.`mZKhhY xxF N_ h]P˒i8ގ&Yi8Xb'V|j<9)XLƵ,TW*I\0%MFԡW iBjgF>3 U|(iovƟ١S@o}[ [xNj 6Weù6aӇy6YLWK^9P+-d6=Ye12KR>y:a7g :Ġ (Nğ+i> ^as!!׿| |<.&̓b9mW9PnЄ LW2e֭s,^A壃h\V7 SԆsb?iG mѤ7So3)ա <]o3h / 2W:y*{;X!XEDVSQ'X((gN[r75i8q)ƳUZT`wn α s\nVX)(F2U+t)3Xxv)PIu\PoO |kUrc^x|_\A!))#huz^c9ZU\7YXb]9Q,^ Q֦5\ / V{1Q!qg7OލHGE1xZ} a?u5_|%~AS%%h׉$S .䉜,d>Xth<]jLۆxi8YhF"MX,D/rUp wa ~}F2R*JJ_ڙuh4b1kSIZ_>inj>+j nxWßZ $ut xwrWZ4=ŶjsiG1_UɸqEE`uj:XLD_RxFYsFК4U8ӧMʯXLJ*d*Xd&qHcrօ{իZl7,8NZs:(1hw5k:ş](vi xq؍{xJk%,چhnbjƍeqYxeXLLqJrΦ27^T!FBJ?CפqZL9fT*3 MRүK iJ5'0R.Xr%5SޝJ>u7Z:?OWh7:r@D..Pk$+q"&*l$=MUsӥI{V,O?V.+Kkwu=v{x&u8|g]ߺ妹Fty>eb8WjR+ {孈UԬۂQcI}g5ۓӋmG-8_rsQV\Ӝz h|9S~ݟ49a>'ҴRDVMF%p(+#a7S0صNnnte *,Iu%9wMSv\̲brq[^tԱ9>!ʥ8QiSs_ >x//|<7~ hx[wZƥַgI34q~ KOOܡN0фaJ<F*1QI$GEdyzT5/mS߫:I^NR{yݾis~G?A3)~gQT>( u'Fmk{K#/kQxZBH.07W3lSQWR|%JӕDX\WV%KKRLL> OJQ~:5ZM^J+4U);(w٩Oc6~$7_"ռ?ϥch$i FyQ\ '7C1ȡJɪS8fb*S\e)sIga- q?,C|3'R1T(*jQj8*kFQi㱉*R|#{'QC~$"ޓFOmC1S߆ AҐ[9<Ӊ뻪0p', S*y K&UL,T~|Cmx㷆G lN.qwe]F4=JD槊2\e(BZq{J\59a+׎p֝,-JoxNpl(Sd)GRvS=!iӔ%TcӒaJh^ 8xG῍4𯁯n_H;XbIʓwM6s>,t5̧OU'`5QB*){򂗩%# Ƅxf^ F`q8'%jpSٞy<7h{Zgi-AZeդ1I{Y'ygiigwo_# *_ڐúv¬' VJr(?}9|.:X\'Vtenh '*3Xjʼ_S4Ԛ>=xY?쫩x{V_@~l>: O7ůx%-uCckkX˲Aiq9K;oA%x.N/^F%a2|5N0ReLE6*҂׫Ӧ..? 缓Ujpj8\:J|*)UIBXʴ*գVY;~<.?e/ڧ|(]İha}T5֏^[;b=OPQ։+5i/,"+Caq_ ~|p8j8jTnqc.-Q10Y!*Rx,V^_Y1+0r9j&b~IJp &x}xoZ’>) H(%X ?Wo}f.g$V7E<=\$\ZQ1PY|sZ7C)4ajl0bJJPb!ajXʄe9U N3O(*llbq'Y:qY5VRu<>"-sP@Or?gKZ~# Z3 U6F_ݝ=]κMkU+*Tγ,^aKP;Rj2NnqB48|ER,rnQ]PnфUkV*+_%wZ7!³~,⇄/x+WX`״GXF>7:{wGkwG',,>7 g^/ q ;ILJ27_Yrm8n!ۓxZ(s(r癜u&b]Ey’'ψ_Uw\|C;oRQ xGSռKuWZOŦ\Gm4[mwgTykƤa4pj*|*xjZ>8Zo/8thKOc(N+}wCNV4ú8`R)}vk㟎xiwj_7ǚuA \Nx^kB&Qg.Z[Xk%d3;kKFpXiRf~ a1bJIfT(ehՍ֑x3[Iq}: |Mx$K#Ӯ/,9u=+1پЎ9JXjN+5Yq(¥%Z#AN8e 671$\-XcNs# <&OG:J1EG 10‰QDQE8PDPT r)Nr99NrnR)JNRmRaS)ӄiӄcBQ!a(1I($I$a%P3ƺ8x?7?mHW)h~fbkz(&|VBaŜ-b六9:x.S[֨(5Q FpSdje6oaON*LFKTTUpجM9sA'<'}6|HnE=OѢf;4EM ZY˦ɵ{Ky/k3}i*pfrI'4*1卣NQKDԡOa"W9^xSڭVI]NJr|Og Q_֮߱./.<x֗WRHu}[ff^Zq =:cQi_MʞS/TT\9T _%ɨ帼ldV*8n.XR*RNu՝qhʍ6Z<k,EJh`p(`WC_Lu[&5Y/d+V{ (? ?~!@o|_< K{k4m@nS(tѼ^HhzlJ _s,_fgTYse_r †SdNJ/&Y %oirbFY*9E\Z툯cq. ^lv5EoSMYoƞ3^jm,mfmm^xGmMck5I[o(AV+.c: 7dٔ\[L^_tq0zVL(˗ E%Y0¼K2!WsbdX|m: 3qLUNPpЯ?s?j)$_~xs*--X-cگ VniQ3Xj?4UC9ljd&29Ye[ Be_hV0Y*ڗwC#GpfL[֞ef=u%N1*^5Q<R}oRڳJem:Ğ|W/?> >z_MXγk1\:u^iΥMHUV9`8.dYUęU\tf9S<>/ZTj֖QT1ص5*O [/o <4lx,-xF*?fl~/30XjXHUQˈbjՅl,0Տ7#w< -W>;z|Io k,4߈.M|EiwZ`W׷" a=Ԣ#%. txW gwxz?[҅{oe T(SQ6s|?<-a3 b8!2>gW3˩[N0qUFU(QT|O?w|, v^3?_OW??@ ( W+o|ԙgc@Ǻ \GhfFUU̱yF;cJjG,pٌXxWV%~ 5)bg /䲷a˲%2u250xZ|ʞ K&ɰ30 **|;B?I##slDs*ᬇ/gY%,!*XzpUqm (U tCᯏ>XxWK׼l I炣{EEд~}q>|I ^RჭJL>ef|<%c3L&pG18ƾ^)\'9[0؜F'w%՜2V'͋qEXgYa*f; za(|'i~x?iſ xEN{eKZl~4[{'?WO𿍡|;^J @nr ^LzA՟ap1LRXoeNUKXqa^80gBU}xC4l/xc ٷɍ)үa3 33'9}"Xe33'N* RGCeѾ$x^ok_ky/|m+bKoe]mWE-&qX&KhF pmӞrJsJ5buPr>VZl*Z.{uqeZ4R꒚Cap.~ F2JW?թM.iI|e,(<6m> A lX,=#_% J~>Evz>wx̚j &]R CHWk{rEF/[)_&&0 FJpK ,?XiG0 gZIaj_+Q"Ԥ_5j<^U:E5I ÿ}#k Gۥǟ5 PZ e_ -rXԮ4+zOv\Iv'Y*xZw&1o7¼q3JZUc' VRxiNR1u< <3ߌ~iFGo Z+{DߊlWEi%\G:(sJ iJ3FUXbMUxj'cʅ }i0E8xC ttF|_kTBSc_?|^E{-X ZWXxĶ69`բx%?7JSP"xׂ*[W*|FpcREc$goXX9|n FTaF(J.eSc:J? C >-^~ɞ2AR| ҴmO r 5/<we,uI c2"7TMeXLVeW:ѕk% ''W Y !4k:uޒX~+эL_ [ݵri{be/_Ü\r%/ fخ>#4f7KZ5+Q:R#xw%YJ2+a-y1Fej?{=jR}Xe_VIzexO_:džUo8|Ie'_eX:pV). eIҊ(EZ4Sg<&i05xWCB#*xum D'RW0W=Lϛ [ N?.|Yy{E|NnƟhX//=!I7y_}SN!G.fFpP#TwȨ((]ߖ׹ I*dyML\<USu~kǥW{@P/IϏIWo#/c fa<~͟7.c+~>Onlm"iNqC33D@[6$^NvFaxnli7ڞVo6zy?;ӣK8̾vQmF2e''ͭx,0=~#᭧_ &J7oڞ#V:өdZopudaЩoih.fԍpuCz|%sP8T½ X"Ntx>qVѯsI綟K1_ԞiƝDL.RV*9x[k)K NM+o mXIFyvtN"$.mcDSX',=k9KU^NXԧ'ݣRI9)jP^N i)JqMR:\W9w(t#cK[? 5oH6ɮ5n|CDk]uNԼA}JizfစXxha*8TSYR\YF`9r*K WӭgB8W)Pq,AS0:GwS שJ+ҭ*h⧊{?H i_|S|J~vƿ57_VO;BMಂI*9yK~.LEujקG4[K*oƧ֭ajkG ˋ:Rg֕|u_x권h*rxl=TZ|>mh`OY9М!Y7/)iV 2:ŎxCkɭ[[\[yqG_T#Da˥ S],43YM޴kG8Ԇ~P@~82K /KM_?Wߟ3$𾅣h`ok*MKy1p֔v^+øM;N.2WR i(]h);O LphQj0Tj`֥&'-O,/ =3',_e)[0r/.وPi~-:SIT8vKIoK*re՟7Tg_WF(E(r=.IK\Xxrx>:ŗY]Zp|Svr<&[CZ4X\=,Mw RBԫ+F 5$fL_⯆h7{;_2[xkvI-sgj^EVMvMJ(4hk3TG측NUs|ңsUTԟq }fy|h8M$zQ&1x<1YT–aF\>xWN\XJ8bJE΍\4o~ʷ?M>#A_OD}O|7h7u.^QQWqPK.x|6.Ro ؚPm O>~Ɵ W(x~&xWxs\kQ ;%<\GkqXmE 6ĵqqlN<XYNO TǯGթU(^ڤYt`wC4vI+6GQɷEJ9*:j]ӌU:ٸaa{SFcԗjr`K9n4/ Ɠa, ;.K7Rf'-.c81A,g}NnѺ򼑯4lO[gf>_'N8ZђjK4OFuH6S8TBQe|gԴS?,]n<%qOd'욄~-ܛyiW۲"-ۅ|וÓVUbTaIUXiٴ;\﫛{S__ D]\EZ8h:%7 F.^?U'B/u_x>8ntCR🈴o閚q{y^_Z{o=͔G4m,ji/<z*{Z/ _ i*SP([=. E7M JJc:ħRRQ֛3w}Qˏ^!j# OJUX<9on.5kFS,"?uKH,~aiZц'' BJrJv&K2RXkY]*&aܡ_bMJ25! ʔ) ̓{ ΍'Hδ1R!FZ?cKC'O»k_煵o=ݼy;u\xZSS|'[C{T4{[t ֮*4ٜ0:jd)є|XFA^JԯSSqF3۸l-JXPC26tiC[5aǚ(er}~5x~*f[A{S-~&|J X^uY/6u5G]~t#BY[]fxV̺1'S5N15u)V^8nQ*cFVaNyvi:V/~9J5#%8JNtIե^3`3]?e o¿;_Ǟ0_'r .Sڏ95 =Cĭm&LXC*^5<\q`pJΌab*ZJeS9Ҡ(P% . *U0Wc*Ubv' W+9KWNGN59h37Z^uX\HP@E~Զ7lOI/hf>2U*-,*rajִ7$u15ppm)V,=O㛭R劓u1aʤV|ECQxO)z>Sԯmu%լcbqy{2k,=?b9VT!t~zo7N >iXSb*{!8ӝya9j2qi׳>:<%9x/6o.|otT>*mku/ݺͨn4$zGgpYYe}qrTƵЦ֧M;LN?=joe0T9 {u>-G <֦MB|N*#^e[, FJiETc=%F'QF93RPZkVu#Bnߴ?d7>/Tմk:EůZݳkꑧْGqm3{|3 N5jgqB q`yר߳RRgB\y~ju+1R6ħ+U\p;խN9| ? ec>&x{H׌!l<; KM׮$ѢyŔzj|kXk?,E|mb0q&&&QReF* HTeG Niac\j5!WC U~\q1tG!8ʓ9 w<I k:=N eu-sel|(S%CS^w^2T`y*?hNP'-GL+ikoԵ+ៀ_jz`wEjZޙuJ`>H-0k6lCx\ NQ*RYp4۫ƬaVsft^ڮ"](c5j{Wc`=uV 4J')*F ԡ_ G .38|4~?xH;&ۄ1'; ?\cWr3(תBRjP@~8z2/ }SRxl]WWn$7&ˉ$;ohp˽ QYՑd6,&y[E N$6ڕ*fFs\5/eWdTpԱ7($]ՄRT ~⎡Kt;?|7Ԯ59;/ 듗4ۣDjWx栰 ԻJkkʺԣ}e(ũsZFn8_}0+6^:8%vqTfxG77%ɟǏ :|%ō2WLj}3>%k| {y8i,SNIҤJ:Oߩ )T8F%54*=RƬr)SiFr]G*Ji+*  ѼUo^ {ƚ_m8?5}:[9tm[Ú%VNRԼ7K|sNԱƣ%S,kC.L]Kӯ(c(aENFUJxȺu'Y.tl.9JPxy{lH^tjA,MU j8Jӝ0P~N3D[4|'y/¶֗vRx/?hPSN+^ Kdφt#"U^\E!>c_,Mz)c,%f;JIb+Ԫ}$< <[4ap8L5GsJM7NPvoV{I~տr>%X?_SUZuVkJT(.Y0g4w7ҩB*uifX6JIb$ӊeQ٩G G xjvee𵮠u%jlDb~4~|Y*,Serz];%}K RWøxAe8uM/mRm;rT$];5#Cj|)(x$<7|Z-}V-?NAѼ3]3R..Ou8n!-4]SN+XF0,iRj1D*j^増׳3|FFIJ=rS4fXkr.~x=chL1#N޿KbGtOK?N\k׺{zN<=y}-Msx9|4X(81ت4]j<ѷ/8´0|:qq\YҜjFSTYRϖqN_ }g|{ii^VW1EWiF*t$()գzl/RHFIӋ~/(<$5쓠Yឥx!AgbmOZ-7F|1[:߷71\.b1pq+|Tˈ˩Vl<GW(vPCU*Y\;~ҥa*Wn\ʝiQR獥Jujs? n獾8MM'|g}jt񮕫IK7J ;I<)a{m'wmt=?3a5!~`9q*gJ^mŨ%W^XtpF%V.ueCX\5*n1գ5**9倍,,p;|d-[7>'UaJN-S>#m6>3a>[ yu+m,ȍ]WJ済*r*C][W(J:t(RH4{'Jzfrdyu*QvmJ#_ I,Kt9TeSJ8*/m/Jeeo_6otռAzŎxltF+?x+PGnFMuYUz(α8ʴ:5qn<ե.|vtԩV<^cԕxa -aSx'.3ø֩f>/|E? E5o|='M'+JNܢ{bw`\yY`ص 'ה}ƽzU&$(g.J:Xm8R# Jt!UA5w4J?;Giy4%:q&Bu'<9AVTI9ӥOJ>u19{ӫ,TaN2`j:4T(kՍ(znn_uvP@YO}#g#:JLl4{fhY<Ӭ-4rST>*B"U*IB*>=&hf2ݣ Rn\VEaǞQ8{tc.W'y3\<of)7{Y| ;uWSWfG$[beV_,1e ĴC+𳄣J^L-,=kU 1Ē\/VLÇPx+:NS$JM.fgJkҼ[mWKφWk_mt}'M 5-GQ%h(kzVʩ¢=vkpz+0$-\jj:(2sΥN|t?$uKBÚgoX-&m6`K%q=ǁZx+G̰*تZUOvti֣7JT+Nj”`Gq8ZF?kzx(SjNT,6&RE(UXjф'9C5%σ_~&Ik&UԼy1Ey7:WPrډK隕ί?fcBΞ_M:\>TJ5*s,}ʌkbT+BT*Ft0J8IqeSg̟pFaP 59­)R:ؚXRu콨~~j?( 7&,t}/Fx]}O\x;M_早_6uhZeRsdq,:L[ =j󧋜UZ5r>>8TJ x{aʳ 7NVSiN5:8uPRxzؚX9c'h_7OW ?4Ѽ mۿ]yuB]_lW)ִLKsZ5u=]#ujknKAɞN6`(CG Ns0upx <96ʭIq+:IO$"j eluW[&'*R8Buk…JqNKgW)|^#A;xoN\̲Zy7腮,~ciTxa2ZtwPKAAJBiM,LJixot_(OUXxWFW:؊J_$Z*5 P( =x}|KP_(}֎=ij5h ⯌CK7*Y\M uk4~KndSc>yC,*_Pɳ:T*1w{9TSqJ^kx/Ūs^ " :=q'U<](֥NrtwNpe'N [:Xch)` 6#Ix<a^Yrb*A|^_E5j8/Tӄ?[a!g?`]\#$g y z8~׼~(P@~ jlcyr-F]N|'bi%q}jy~W''Fi昪+F%l 9ROѧV?peF,foJ1X.O$N6 <%jTUpS9ikW㿏g߆7z7 o [C%’x'.N- dѬuk0C5:\\C }aYnsIW7Sʰظ׫կx^(Jx04 i? ]Ugj3+yFsI >JR_ .4ӯBpj4>uJ3HF!'׵/rYվ(zC:qkM']\>Mx<;hz}ץbʥJVΩ*i8Myξ2maS:l LߤYFS:L^GSTr ,O`iҩqXS_5_|['l|{\=%ƒ(Jug g=ĹU.;l1t`J8c*ʴN2* N1>+1_? (H$o $eXm# 8=Av#X(FJF&ں AVuT$8h(;'guzwwA?{w~_cGY]eYJmе;{y@f{ᑫVxTRVTbYBP)Yhҿ+Q3){%%,#5R̳Ӕ'-j/cZ+­))OFoaE'G~V=tes}6Ե|Y+q^tNzԝl6AB4ⴻҮ/rvN3GiWQǎ¿_2i|H=c^t OQGOm <:5Lڼ}333$`rʸhK|jW&!WƤjF)T,҆UCX\WgZr1xI:8'N:x~_c:5iSaߏe`ڃx;Zw>x~]j?ӭN}Ξ5wk\GSV>ӑ֩䘋ٖ[}%:_ٔ!%^a qU01TqT!JSCڕjh,ЃkЌaJ*Ч)MG7BngV,FRhvke-xMI.5xղ xCԴi E=K3a؊ϷrqF^چ']Eaq62Ԣ%+?5w#7YNmp-Ш(DU,+º ǰVrڕ\ YQT,RQWYqVT+PG4qJX)c'O*3xM]Ft'SS|`^)74Z;x(eV%A@PgSEguvFOg=^i]luk(턐SG32RˈCqv+,džX\/ׯGyS9*_F^Jp/6 NiPs)N1T6n1THVNY}4ؿơr\x> 2?յLӭ($s{u BQ]S J+L%pҔ5+X\=zK_gJo[$zY;QWcgiɻE:>:4۲NZA_ީ8EsI2oks%j?5NGֵMoV>(XMZĽsMyòbSi{%׺dJ'(Q#qL'bそ|G9F+WY3 T8q5 J_JxԯWVpE81~ ԡ_P i`Bù,ÒRRx*4!I7m/ڗ4mcxoڴ fӮ_N+M8YM.XSOӤ{.^/G,65IN+NS gg]w<=ӟt=bR׿f_9𯈼[cuc%gGBV qi#:UqP6' <-* S R8Xbp *Xj14#xR )饉4gMPNraUkR10t!VW92cR5?e/!/ؗfS -|7o,w_X_jE|e3x(K񏉼-_z/Űkcqi߄,.ЅY]WW 68IKB(WC~ l=z8gArʔ 3mZeQGƣaSXRUUWF/S "jW[  )7|6~('~|Oѥ}7N-`q5:>z.-(uΑ X&qU;FN{ڱ3:*`ЩO%ZUoL*ƞR/}zR'Vl!Uf8?<&"uf+Z:Ts|e:S?TµJ/8LdkLi%X@P@OĿ'>?'_b'_@ʬXVYX`AdFpHg pR%iFQwRiӳMũEM4ZM=SO~j 58~~=W^ ý;4^8o<&_P;[D"iq;-VfoK.[JX{Ԝq(US UI*^"t劭Tae~IV,5ZU`TKrqQ(UTK_.R=Q xֶ ,P+>:j8Х G B>ʔ)J$9[V))Ժq)PhaӒիS؜Uy9թ+QJNvsZGW_~߱oA!-iO*'QhRziTJT– JGg*N^(Af^UjBgMNZ׊jIַ$)RB_~8|>0Yw6뺽<_ A}?(RJ.HmbTӬ{'R.*hp0pЋI5MEs:t*4h—4i֫WTuq8DjNZZsbV엪Kľ0/Ɵs;Mׂ|}7Mxcƚ=ֵܾ=6&^;MV rЄjXu[Bp炧Qᰕ佥,&VJQRi8ӏMjb26s:uƤJ)5SI{Oqp[Ze:Zwg?]ߊ!OO~={_OOg.,7[Ku:nomhLYڟDq:|z6zuU)R>5 ;֗412uig a_aRTiU^VF@P?fx?_^/ÿ 5)5O|qgo=Yƙ}m_ioe7ѵ+mmԵx/9G0t1J%N,NqaRU!1.>ެeJJsS\%L&kgV 7 |E7 G:KQRtUiW+P5 =o|hſ|o^< ۛ׬]> [y*kwד :6quSOQc(<-lTԜq PE R^]&NDgRZ514hkaBiRStN&a+:UhӫE'N49Ԅk>MW¾?<[j CU[šŞobt\_iZͦFӌX[VM:x9Ka3j/JFb)hJttB\EQn*N7G:u'8:TqT sA{I4jZ_ڇ|[y蚏|; x+߅u2ʾ!+¶QYk>&XmVtK ).t觏p6J'ɂur|^YՕJj E u#hԯV*tTӄ):p#AE)J|oqZV4??&< sǚgx|Mf[D>}Y5b\Q|;2X^Cg9{GӴk82Rx*jxRUTeQJP9ƤkZJQ1Ԓ8b}n3R UZ8jiƍ)VprJвJ0;JSrY)w ~> \i[~=o|U%Qyúeɳu=& ͝[-̽5*{Gq oM9 _TN|>/~~ϟ '5=*)kEMwww&g[׵[xXԐr\[gV:eeeeki˛a`TˡPVUR'9u֔)UԨe~Jxc9JJF0|F\œy9r_OzIMR:ߛӢCOUKYZb+QKw^"xҧ^}:T( TT)sʤhF:4+W'Jx)ҽ% kKJ2NvO|3ǃ~~&}{IuKho|-BG@Hv: ou+gpl9xXJ!Q^i!s*Ta+NxJt__2Ju*Ɵ58R&⩨Ny҂FYԢ> |u ~ޛO# ֫j_5)W(H`OKW$SC `{0©s8N:=Zg^Z'ņ ;*j؊=LMkF.faN0EB!_g5mS^>'Ѻj^4jZėW׷_ gY.n&ywYٙiStS:p!J1VZ%MyTSRU`s=)Ӎ%:jЧ b>dxu/ 8<1Zjv=+1+sq *}wCRau],tmsO4xm& qrl5N(\E|N,]ciJ> quKuVԩK <=tzxlM7VY(ԝz3Z5!!(8<|/~p?(ŏi:uOh|݉_ /6zwvz;8.U.+jJqX–'9:s(I}W9FpyIOEvaV8Э9K aqh,LWk^2Nt4ҡ>G<x]ώ߲Ÿǟ "xŶ\júŖ5]/YK[hإ]&L QXfW6)QRQۣ|\U|%^XabT>XץVcײڹUj6QѧCN3|J(9/FT)Q>꺖x7 J'9s%Iz8V58NH+ b U7TUa )O9,F!RKQd/et=#_?V߉Oow{{◁n쬼WԠ6c燵|kYuo Z}Iy ļf+Crs:ZO嫆/iF9ƯDakuTN VJU8Szu~<|ON)~>Px).Sa>O>KJeYNw}mAP#ORJ!XWzwZtUYUTb)Q uj5G 9cIV8EJX.4N9ABԩ<%~]xG]er}x7z<֮ڍ֢0/P8N[Q•ap6ni;k۹KCSy. Fi/.igc[֭:򋕣ESN MNz.iJrnu*JjZI˞P\)ԫVZRM1# tF4PN>Ix+iMsCoIbxΡ{-4- |:wHtK3GR+5[EˇzjWÒ2U֡RjCBRRSrswNeQT,)ҫFmN\\\ҒMJ\RJ?H| CuUZR_& ѡIiNVq8z8|E5Se[]>LFrU9J %:#uq1b W'i |}?6K};>+t=pL79cixp^G< ongZ-޼U 1tp'ά:R)>Xaz:5S+Fx% SJ)TUbKgiPh׉41 *qk7Wejz1R7)rn JU|#V嚫,6#ޜEҥ8SuW\LQT|(⧊G:ʥ9J\`G݊IPg )xo㿊>HF5xNѼ;{[gk{#Z𿊴GH!PҤ͕9qXЄfXZ"X M GT7z n2MUS5L;(p_PEԡ B:sNJueʵ*FJt)_|{cMдKq2K<;}AXF{M,Z_jsCcYbqQPcjT\UZ|NR0k9ڍpC:8i1\Iʮ ƞ5Vb" U)]P\c⦙i,)}%OV[MNZ𿉛jz]ApU$ ^yJ'F?k:2Udj.4 QjQz!WT)UUU9CF}yUup4Ѵ5/=?VSoС?xD|%q;[vR|;/tڊZjWַ6z͜5(GN>O B).jQ TEGХJ)8)҄"P."jbqQbtN62.|IVRJҕhVNG?k3@ (|1ž!?{]¾*ү4M{GuM yżKmyi4W)ݜ]C #OFTj' '8T8գVF!VTdcjµ(1%E¥:xUVJ*TҜԌ)F_ G xڻ%sk>'ѣxዹ^[ Z|Rí[vQ#g=f>$O2O_*nRX5Xƚ{(ib5J7Z8'^U8F*:SOO)<<9U؇9*ԫ/?g߆3to/]߁#t;,y"QKכY{d'ԵPdTKYc4O7JQ~Vj>6%%8XgӧNJqT9s+mŪ_o֎5v'/g*|I0|+?4:U⯇76"|osg)eĬ頄XiHV}1ҎcBJ†zPBLR SnPJ'BR Y 8yV&R2Q:rASRHƺMK<7 |Fgg/7o |:{ IZ֋[Jcn.UBi^QVZT${ok4xVԾ"<~ǎK5^ݚ I,pXLbUVG/JtiFT5;{Yת\*B8T>R0'Z5e^/JIF.J1KߝZj_ ~2Mi{W^xU >*[I4\^j˫J]qG=zQb*baJ T=t)b\х4n 1i8s/kV+K)}YQuVДs5r0#|W?C@[}Y5?o{>:֢u_&m{]#Gm,4.Y뫭}cN8|uR)^%uMʥ|f.tS'*=E%.IOW^kF9T# 4*j48R4:rJF@Pȟd?Ŀ¿)} |3_'x}5u Y?vi,?fj]:P|F.p*a%^MBp;`֤(R*upTKMƝNztإMR*U3TG+#㇍~?jx~|?|7(X~/j>L2(Q/%Ǘ ?WڨQ8b*TTT+NIΥLDZҫ)M;_ ~ϖE犾Zwou=VVo5GNJ>}6e}ri7ks-v\*1N,*NfСTnMUp&9s)Tp.Y|R:咜q~V8ʌU:NNr:W߇߶?? *ig5 |6G4 kD4O J:u*ݖEgAKku3YU֫-JԤ\4c:ғ+ԚqqNtiPGV4S(ӡZM*[(ҩ*rRnqW U>iV`ֵmOUW|I:ˬ:7ZƿLw8ӭ,֭gRz1KЎᰘXJs iu'/zS)IeN$UJ'^JuqyJ*1,R#y9^eE~/ft?|Vo\閺n_&։O-J]V]<rPX2iZh^g9檯JpRWJ' sjwΣ8S jSRQ5c( kE44>xr?xž # |H&->"x>xL5.F<3i:4_aO cs1s=pGXa1qXyS\W*Mg<Ftc.hRxh%SC j2L&SyuaVp7˱u*ju1e ukUKip:q^)F/Ì-VcЫ $J1fRĨK W%~''f^RzxlF 2FF/R(PtR:KVE^3/fet12;X8RRz&oby[LQ(S,<+>o ~?+b˰8c(exL540\8l]y,F+Ji9U1_X^ʸ;&J~sѣ:ui34CRX v=z8uП'4L)|>xvo׼/c> MoMٹGM'XҢOwC76ooO洰X$0x [ O^%u#<LD.#ozziʊJp:PNγ f,ӈ2W^aV8(Ԣ~TB|73<'~_ R SQ?xZ=RSh4{H^Km]`ἾKQidɾOfXJXT2]l5l5X78b!_jZr&麝pX"qYp8<> (Ԅkf*JHFOWUg:2p703_1̳(d^X78fO94|V4!N`|u~_O6P>Bм>-<qix_S5 X_i'B4*[K*JhMymrM̪"HCjU)֦E:S*MÖYqF],VͲc\g 8V]-:ԫG B*ƪ= Ok~Im֝]x O^7귶Zmڮ{w*0;+[h=8pu</h[s9:znJSQM#81!692xLp598•*8zrIƎ:T){ZkJԫ֯Yԭ?7 nKox_e\ikПSBIMfHC_ ׶{{ _'>Og*Wϩ{ r:c+ZI{J#.JS(aʣ*9/2|4_ e9w ،R#븹֞}R4SGa.!ũN48vj*+M?ᗁ>3|?_o;߅2mL6+FIBN:RkѩR' ^J=Z+ӝ*#?~4?h ]'GΧO0<4Xþx2_666asi]rNgKRϞO)6/s~UNui.U VͣyVrjLbeJx8K_=3|_?ZXEzx#tNr8wSTJ\EU(P֯U?Y o{g~waŨZx]~ 89gؿPxRaZQxjtp<# T(Re'W[1}<  (ȑIk^Kⷊ|KmmEߋx6}K]Oln4H"XH Im7{FFYiʜqkyС*rYNCK"xII۽bo mLSGU-M=Z[ညp&^>jeQTg^&bƸ~HӧV:Ư+j'ʖ ]JT*x:7NҥHʪsO+M־(^qI+~.kZ|_ZLV: '9J 8}W R R¦!sEcsNxP*'!+ztj1SFU}W( ?JGWI>׬Da2^Gc٤iuisksuc}iueuqnJlUpؼhNTQz(˚iƕzN&-izR*tkЪV +٦ 3NΝE:3J8j."? o~$kaWN4Z+]~G C.=w1Cn'MƝ575OBXY#bJJ Ҍ04ՌU|ZgI{垕iW{^in- .K")(h9qT#WVUci缥^x|N*qu;|RSdtaj}RZ)҅ eZq ѫJ4Oz3%R*~ o音Vx~m/ZkW.2t_V+9-k#a4l o=tfV**NXw(!<<*^Bj,M UX5xë́|,T½G11XՌT#iש*t%BiUʕj4C?dߌV3i ?4Kv&e~_ Ci<10K]Z=yqw-WSkڛ5r֚VV[tXE<,`],,8ʔ99GK:V2z6&NL{ӕ,SݕG^'J<7Fc?bËƟʹ~ Ѽ^,-kx⶟|G+hdvKu$ٞDN45iVѧ*pץ7:Sa>ZJ0.JЧኅ: u)`B)P_BE%Rd8QkE}Znxyե?< o |4M~hOYùeIn&yn'/gi*RJ1c p:TӂPJ(BTiҥS &(ST&9)JYʭZrJIɻroK]`lP@P@( ( ( ( ( (݅ީi| sSVVT=ޑyom*DK2-9? G |Je-|G%i.oz.h\]IujLW3LRP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ntl-11.5.1/README0000644417616742025610000000122114064716022015031 0ustar gid-shoupvpug-gid-shoupvNTL -- a library for doing numbery theory -- version 11.5.1 Release date: 2021.06.23 Author: Victor Shoup (victor@shoup.net) NTL is open-source software distributed under the terms of the GNU Lesser General Public License (LGPL) version 2.1 or later. See the file doc/copying.txt for complete details on the licensing of NTL. Documentation is available in the file doc/tour.html, which can be viewed with a web browser. For a detailed guide to installation, please see the appropriate documentation: * doc/tour-unix.html for unix systems * doc/tour-win.html for Windows systems The latest version of NTL is available at http://www.shoup.net.